require.ss
(module require mzscheme
  (provide define-module
           define-library
           hygienic:define-module
           hygienic:define-library)
  
  ;; define-module SYNTAX
  ;; (define-module <name> <mod-spec>)
  ;; Binds 'require-<name>' to a macro that expands into a require form
  ;; for the given module spec.
  ;;
  ;; (define-module list (lib "list.ss"))
  ;; (require-list)
  ;; ==Expands==> (require (lib "list.ss"))
  ;;
  ;; define-library SYNTAX
  ;; (define-library <name> <package-spec>)
  ;; Binds 'require-<name>' to a macro that expands into a require form
  ;; for the given module spec, but taking the module (file) name and
  ;; optional additional subdirectories at the point of usage.
  ;;
  ;; (define-library dr (lib "drscheme"))
  ;; (require-dr "debug.ss" "private")
  ;; ==Expands==> (require (lib "debug.ss" "drscheme" "private"))
  ;;
  ;; (define-library dr-priv (lib "drscheme" "private"))
  ;; (require-dr-priv "debug.ss")
  ;; ==Expands==> (require (lib "debug.ss" "drscheme" "private"))
  ;;
  ;; (define-library schemeunit (planet ("schematics" "schemeunit.plt" 1 2)))
  ;; (require-schemeunit "test.ss")
  ;; ==Expands==> (require (planet "test.ss" ("schematics" "schemeunit.plt" 1 2)))
  ;;
  ;; (define-library project (file "/home/hacker/project"))
  ;; (require-project "app.ss")
  ;; ==Expands==> (require (file "/home/hacker/project/app.ss"))
  
  
  (define-for-syntax (join . args)
    (define (to-string x)
      (cond [(string? x) x]
            [(symbol? x) (symbol->string x)]
            [(identifier? x) (symbol->string (syntax-e x))]))
    (string->symbol (apply string-append (map to-string args))))

  ;; define-module
  
  (define-syntax (define-module stx)
    (syntax-case stx ()
      [(_ name mod-spec ...)
       (with-syntax ([name
                      (datum->syntax-object #'name (join 'require- #'name))]
                     [name4stx
                      (datum->syntax-object #'name (join 'require-for-syntax- #'name))]
                     [name4templ
                      (datum->syntax-object #'name (join 'require-for-template- #'name))])
         #'(hygienic:define-module name name4stx name4templ mod-spec ...))]))
  
  (define-syntax (hygienic:define-module stx)
    (syntax-case stx ()
      [(_ name name4stx name4templ mod-spec ...)
       #'(begin
           (define-require-form name require mod-spec ...)
           (define-require-form name4stx require-for-syntax mod-spec ...)
           (define-require-form name4templ require-for-template mod-spec ...))]))
  
  (define-syntax (define-require-form stx)
    (syntax-case stx ()
      [(_ name require-form mod-spec ...)
       #`(begin
           (define-syntax (name x)
             (syntax-case x ()
               [(name)
                (datum->syntax-object x `(,#'require-form mod-spec ...))]))
           #,(if (eq? (syntax-local-context) 'module)
                 #'(provide name)
                 #'(begin)))]))
  
  ;; define-library
  
  (define-syntax (define-library stx)
    (syntax-case stx ()
      [(_ name pkg-spec)
       (with-syntax ([name
                      (datum->syntax-object #'name (join 'require- #'name))]
                     [name4stx
                      (datum->syntax-object #'name (join 'require-for-syntax- #'name))]
                     [name4templ
                      (datum->syntax-object #'name (join 'require-for-template #'name))])
         #'(hygienic:define-library name name4stx name4templ pkg-spec))]))
  
  (define-syntax (hygienic:define-library stx)
    (syntax-case stx ()
      [(_ name name4stx name4templ abs-mod-spec)
       #'(begin (define-require-abstraction name require abs-mod-spec)
                (define-require-abstraction name4stx require-for-syntax abs-mod-spec)
                (define-require-abstraction name4templ require-for-template abs-mod-spec))]))
  
  (define-syntax (define-require-abstraction stx)
    (syntax-case stx ()
      [(_ name require-form abs-mod-spec)
       #`(begin
           #,(if (eq? (syntax-local-context 'module))
                 #'(provide name)
                 #'(begin))
           #,(syntax-case #'abs-mod-spec (lib planet file)
               [(lib dir0 subdir ...)
                (eq? 'lib (syntax-e #'lib))
                #`(define-syntax (name x)
                    (syntax-case x ()
                      [(name module-file . morepaths)
                       (datum->syntax-object
                        x
                        `(#,#'require-form 
                            (lib ,#'module-file dir0 subdir ... . ,#'morepaths)))]))]
               [(planet pkg subdir ...)
                (eq? 'planet (syntax-e #'planet))
                #`(define-syntax (name x)
                    (syntax-case x  ()
                      [(name module-file . morepaths)
                       (datum->syntax-object
                        x
                        `(#,#'require-form 
                            (planet ,#'module-file pkg subdir ... . ,#'morepaths)))]))]
               [(file abspath)
                (eq? 'file (syntax-e #'file))
                #'(define-syntax (name x)
                    (syntax-case x ()
                      [(name module-file . morepaths)
                       (datum->syntax-object
                        x
                        `(#,#'require-form
                            (file ,(path->string
                                    (build-path (apply build-path abspath 
                                                       (map syntax-e (syntax->list #'morepaths)))
                                                (syntax-e #'module-file))))))]))]))]))

;  (define-module sb (planet "syntax-browser.ss" ("ryanc" "syntax-browser.plt" 1)))
;  (define-module list (lib "list.ss"))
;  (define-library schemeunit (planet ("schematics" "schemeunit.plt" 1 2)))
;  (define-library stx (lib "syntax"))
  
  )