Tuesday, August 11, 2009

Handling Pathinfos

In Perl & PHP, pathinfo is a very handy way of pushing extra information for the script to consume. We also would like to have such capabilities in SHP.

Since we are writing in scheme, it's easier to manipulate the pathinfo as a list:

(define $pathinfo (make-parameter '()))

Our previous path matching algorithm depends on the full path, and if we did not find anything we return the not-found path. Now we want to insert a partial match right after the full match but before the not-found match.

There are two possible approaches - matching from the beginning, or matching from the end. If we match from the beginning, we slowly build up the path until we find the first file. If we match from the end, we slowly remove the path until we find the last file.

If the path is very long it is possible that most of the path are simply pathinfos and hence it would be better to match from the beginning.

If the path looks like a directory (i.e. does not end in .shp) we'll add index.shp to look for the match. With the partial match, we can then push the remainder of the path into the $pathinfo parameter as the pathinfo.


;; test to see if the segment looks like a file name (i.e. *.*)
(define (no-extension? segment)
(regexp-match #px"[^\\.]+" segment))

;; partially matching the path from the beginning of the path
(define (normalize-partial-path path segments (default "index.shp") (not-found "notfount.shp"))
(define (helper rest path)
;; if we did not find any match return not-found
(cond ((null? path) (build-path path not-found))
;; then we test to see if this is a directory path & whether the default file exists for the directory
((and (no-extension? (car rest))
(file-exists? (build-path path (car rest) default)))
($pathinfo (cdr rest)) ;; updating the pathinfo so it can be accessed.
(build-path path (car rest) default))
((file-exists? (build-path path (car rest))) ;; otherwise the segment is a file and see if it exists...
($pathinfo (cdr rest)) ;; udpdating the pathinfo so it can be accessed.
(build-path path (car rest)))
(else
(helper (cdr rest) (build-path path (car rest))))))
(helper segments path))

(define (url->shp-path url path (default "index.shp") (not-found "notfound.shp"))
(define (helper segments)
;; test for full path first and then partial path.
(let ((script (apply build-path path segments)))
(cond ((file-exists? script) script)
((and (directory-exists? script)
(file-exists? (build-path script default)))
(build-path script default))
(else
(normalize-partial-path path segments default not-found)))))
(helper (url->path-segments url)))

(define (make-shp-handler path
#:default (default "index.shp")
#:not-found (not-found "notfound.shp"))
(lambda (request)
(let ((terms (file->values (url->shp-path (request-uri request) path default not-found))))
(parameterize (($pathinfo ($pathinfo))) ;; reset the parameters
(let ((proc (eval `(lambda (request) . ,terms))))
(proc request))
))))


Now we can enjoy the usage of pathinfo just like Perl & PHP!

No comments:

Post a Comment