simple config useful? added by certainty on Mon Jun 13 18:48:30 2011

(module config-list
  (config-ref config-subsection config-let)
  (import chicken scheme extras)
  (import (only data-structures alist-ref identity))

  ;;post-process is applied even to default-value
  (define (config-ref cfg path #!key (default #f) (post-process identity))
    (post-process
     (cond
      ((null? cfg) default)
      ((null? path) (or (and (list? cfg) (car cfg)) default)) 
      ((alist-ref (car path) cfg)
       => (lambda (new-cfg)
            (config-ref new-cfg (cdr path) default: default)))
      (else default))))
        
  (define (config-subsection cfg path #!key (default #f))
    (cond
     ((null? cfg) default)
     ((null? path) cfg)
     ((assv (car path) cfg)
      => (lambda (new-cfg)
           (or (and (not (null? new-cfg))
                    (config-subsection (cdr new-cfg) (cdr path) default: default))
               default)))
     (else default)))

  (define-syntax config-let
    (syntax-rules ()
      ((_ cfg ((var (path path+ ...)) ...) body body+ ...)
       (let ((var (config-ref cfg '(path path+ ...))) ...)
         body
         body+
         ...)))))

;; tests 
(use test)
(import config-list)

(test-begin "unit-tests")

(define sample-config
  '((connection
     (username "test")
     (password "testpass")
     (another-level
      (yes "yes")
      (no "no")))
    (logging
     (destination "/this/is/a/test")
     (levels (error warning)))))

(test "non-list-value"
      "test"
      (config-ref sample-config '(connection username)))

(test "non-list-value second pos"
      "testpass"
      (config-ref sample-config '(connection password)))

(test "list-value"
      '(error warning)
      (config-ref sample-config '(logging levels)))

(test "default-value"
      'just-a-test
      (config-ref sample-config '(i dont exist) default: 'just-a-test))

(test "post-process"
      '(warning error)
      (config-ref sample-config '(logging levels) post-process: reverse))
      
(test "config-let"
      '("test" "testpass")
      (config-let sample-config ((uname (connection username))
                                 (pw (connection password)))
                  (list uname pw)))

(test "subsection"
      '((yes "yes") (no "no"))
      (config-subsection sample-config '(connection another-level)))


(test "subsection+config-let"
      '((error warning) "/this/is/a/test")
      (let ((subsec (config-subsection sample-config '(logging))))
        (config-let subsec ((dest (destination))
                            (lvls (levels)))
                    (list lvls dest))))