How can I extend Racket's reader for better path handling? -
i've been working on converting static site generator wrote in python racket. learning exercise know racket better. i've got racket version working, there 1 thing better python version: pathlib.path object. generator has lot of path handling, looks in python code:
render_template(root / "templates" / "index.jinja") whereas racket code looks more this:
(render-template (build-path (root) "templates" "index.jinja")) i find ability read paths cleaner in python code, i'd modify racket reader able support following:
(render-template (root) / "templates" / "index.jinja") playing around readers, figured out how make kind of expression work:
(render-template / foo / templates / index.jinja /) i'd ok syntax, can't figure out how evaluate path elements racket expressions , not strings. if did figure out, still have issue naive string handling cause problems like:
(render-template / (root) / (string-join (list "templates" "subdir") "/") / "index.jinja" /) so, advice/input on can here? :)
if understand correctly, had this:
(define (root) "/") (define (render-template path) (displayln path)) (render-template (build-path (root) "templates" "index.jinja")) ;; => /templates/index.jinja what suggest changing render-template may called multiple path "parts" -- , handles calling build-path you:
(define (render-template . path-parts) (define path (apply build-path path-parts)) (displayln path)) now can call this:
(render-template (root) "templates" "index.jinja") ;; => /templates/index.jinja incidentally, calling original way still works, because build-path act identity in case:
(render-template (build-path (root) "templates" "index.jinja")) ;; => /templates/index.jinja i think "rackety" way. 1 nice thing s-expressions don't have type "separators" , or /. spaces suffice. , think more read , write racket code, more you'll feel way.
granted, perhaps rackety thing of ability make own little (or big) languages. if wanted "dsl" write files consisting of paths, might 1 thing. in case i'm not sure see big win.
if anything, maybe want macro makes / act whitespace in context. i.e. make / mean "nothing" needs be, in expanded code.
for example:
#lang racket/base (require (for-syntax racket/base syntax/parse)) (define-syntax (render-template stx) (define-splicing-syntax-class pp (pattern (~seq part (~optional (~literal /))))) (syntax-parse stx [(_ p:pp ...) #'(do-render-template p.part ...)])) (define (do-render-template . path-parts) (define path (apply build-path path-parts)) (displayln path)) (render-template (root) / "templates" / "index.jinja") ;; => /templates/index.jinja (render-template (root) "templates" "index.jinja") ;; => /templates/index.jinja note / optional here. treated whitespace.
also note real work done in function, renamed do-render-template. macro wrapper. it's best macros little work necessary, , things can functions functions.
but again, wouldn't bother macro, i'd go approach suggested above.
update: p.s., if understand correctly, python's pathlib.path defining / operator? well, racket doesn't have "operators". has functions. , math functions / accept number of arguments. instead of 10 / 5 / 2 write (/ 10 5 2). which, really, brings full-circle build-path: function takes number of path parts.
i suppose rename build-path /:
(require (rename-in (except-in racket /) [build-path /])) (/ (root) "templates" "index.jinja") but isn't operator overloading, because these plain functions not methods. and... wouldn't it. :)
Comments
Post a Comment