rest-bind procedural arguments added by andyjpb on Tue Oct 14 01:32:18 2014

(import chicken scheme)
(import-for-syntax chicken srfi-1)
(use data-structures)
(use intarweb uri-common)

(define-syntax define-method
  (ir-macro-transformer
    (lambda (expr inject compare)
      (assert (pair? expr))
      (let* ((proc (car expr))
	     (defn (cdr expr))
	     (_ (assert (list? defn)))
	     (_ (assert (or (= 4 (length defn)) (= 5 (length defn)))))
	     (sig      (first defn))
	     (name     (car sig))
	     (args     (cdr sig))
	     (pred     (lambda (x) (not (eqv? '#!key x))))
	     (params   (drop-while pred args))
	     (params   (if (null? params) params (cdr params)))
	     (uri-args  (take-while pred args))
	     (mutate-args (reverse
			    (fold (lambda (arg args)
				    (if (list? arg)
				      (cons arg args)))
				  '() uri-args)))
	     (uri-args    (reverse
			    (fold (lambda (arg args)
				    (cons
				      (if (list? arg) (first arg) arg)
				      args))
				  '() uri-args)))
	     (proc-args (reverse
			  (fold (lambda (arg args)
				  (cond ((symbol? arg) (cons arg args))
					((string? arg) args)
					(else (abort (conc "Cannot handle " arg)))))
				'() uri-args)))
	     (uri/req  (second defn))
	     (writer   (third defn))
	     (reader   (fourth defn))
	     (header-reader (if (= 5 (length defn)) (fifth defn) #f))
	     (proc-args (if writer
			  `(,@proc-args body)
			  `(,@proc-args)))
	     (proc-args (if (not (null? params))
			  `(,@proc-args #!key ,@params)
			  `(,@proc-args))))
	;(list 'quote
	      `(define ,name
		 (let* ((writer  ,writer)
			,@(if header-reader `((header-reader ,header-reader)) '())
			(uri/req ,uri/req)
			(uri     (cond ((request? uri/req) (request-uri uri/req))
				       ((uri? uri/req) uri/req)
				       (else (uri-reference uri/req))))
			(req     (cond ((request? uri/req) uri/req)
				       (else (make-request method: (if writer 'POST 'GET)))))
			)
		   (lambda ,proc-args
		     (let* (,@(if (null? mutate-args) '() mutate-args)
			    ,@(if (not (null? uri-args))
			      `((uri (update-uri uri path: (append (uri-path uri) (map ->string (list ,@uri-args)))))
				      ;(_ (pp (uri-path uri)))
			       )
			      '())
			   ,@(if (not (null? params))
			       `((uri (update-uri uri query: (append (uri-query uri)
								     (list ,@(map (lambda (param)
										    ``(,',param . ,(if ,param
												     (->string ,param)
												     ,param)))
										  params))))))
				   '())
			   (req (update-request req uri: uri))
			   )


		       (fprintf (current-error-port) "\n\n\nREQUEST\n")
		       (write-request (update-request req port: (current-error-port)))
		       (fprintf (current-error-port) "\n")


		       (receive (reader uri response)
				(call-with-input-request req ,(if writer '(writer body) #f) ,reader)
				,(if header-reader
					'(values (header-reader (response-headers response)) reader (list uri response))
					'(values reader (list uri response))))
				))))
	      ;)
	))))


-----
(pp (define-method (account/info (uri (lambda (arg) (string-append "hello-" path)))) "https://api.dropbox.com/1/account/info" #f read-json))
(define account/info
  (let* ((writer #f)
         (uri/req "https://api.dropbox.com/1/account/info")
         (uri (cond ((request? uri/req) (request-uri uri/req))
                    ((uri? uri/req) uri/req)
                    (else (uri-reference uri/req))))
         (req (cond ((request? uri/req) uri/req)
                    (else (make-request method: (if writer 'POST 'GET))))))
    (lambda (uri)
      (let* ((uri (lambda (arg) (string-append "hello-" path)))
             (uri (update-uri
                    uri
                    path:
                    (append (uri-path uri) (map ->string (list uri)))))
             (req (update-request req uri: uri)))
        (fprintf (current-error-port) "\n\n\nREQUEST\n")
        (write-request (update-request req port: (current-error-port)))
        (fprintf (current-error-port) "\n")
        (receive
          (reader uri response)
          (call-with-input-request req #f read-json)
          (values reader (list uri response)))))))