我正在使用Racket网络服务器编写一个小博客(需要web-server/templates, web-server/servlet-env, web-server/servlet, web-server/dispatch
)。每当我想渲染模板时,我都会这样做:
(define (render-homeworks-overview-page)
(let
([dates
(sort
(get-all-homework-dates)
#:key my-date->string
string<?)])
(include-template "templates/homework-overview.html")))
定义一个小程序,为模板提供所有必要的值,在本例中为dates
,然后在模板中使用。到目前为止这种方法效果很好,但我想也许我可以在所有渲染过程中删除let
,将它放入一个更抽象的render-template
过程中,然后由所有渲染调用程序。或者,对这个更抽象的过程的调用可能变得如此简单,以至于我不再需要所有的小渲染过程。我想提供值作为关键字参数,到目前为止我得到了以下代码:
(define render-template
(make-keyword-procedure
(lambda
(keywords keyword-args [content "<p>no content!</p>"] [template-path "template/base.html"])
(let
([content content])
(include-template template-path)))))
这将为模板中显示的内容提供默认值,并为模板提供默认路径并采用任意关键字参数,以便任何渲染过程都可以通过将其作为关键字提供给模板所需的任何内容
但是,我无法运行此代码,因为存在错误:
include-at/relative-to/reader: not a pathname string, `file' form, or `lib' form for file
呼叫template-path
中的(include-template template-path)
带有加下划线的红色,表示错误已存在。但是当我用普通的字符串替换template-path
时:
(define render-template
(make-keyword-procedure
(lambda
(keywords keyword-args [content "<p>no content!</p>"] [template-path "template/base.html"])
(let
([content content])
(include-template "templates/base.html")))))
不会发生错误。似乎Racket不知何故想确保给include-template
一个有效的路径。但我希望这是程序的价值。否则我不能写一个完成这项工作的程序。
此外,我希望提供给过程的关键字的值对模板可见。我不确定,如果是自动情况,或者我需要在let
调用周围放置一些include-template
,因为我无法让代码运行,为了测试这个
我该如何编写这样的程序?
作为我想要的理想程序的一个例子:
render_template
我可以提供我想要的任何关键字参数,并渲染我想渲染的任何模板。我也不太明白,为什么包括像"rm -rf /"
这样的东西会损害任何东西。对我来说,似乎网络服务器应该只检查是否存在具有该名称的文件。显然它不会存在,所以抛出一个错误。这怎么会导致任何不必要的损害?因此,我不理解限制可用作字符串模板的路径的原因(除了变通方法)。然而,这可能对于一个SO问题来说太过分了,而且应该提出另一个关于“为什么”事情的问题。
答案 0 :(得分:1)
如果要将include-template
与变量路径参数一起应用,可以将渲染过程定义为:
(define (dynamic-include-template path)
(eval #`(include-template #,path)))
该过程将任何模板路径作为参数,并包含该模板。例如,(dynamic-include-template "static.html")
会呈现static.html
。
这可以扩展为接受任意数量的关键字,并使其在呈现的模板中可用,如下所示:
(define render-template
(make-keyword-procedure
(lambda (kws kw-args
[path "templates/base.html"]
[content "<p>no content!</p>"])
(for ([i kws]
[j kw-args])
(namespace-set-variable-value!
(string->symbol (keyword->string i)) j))
(namespace-set-variable-value! 'content content)
(dynamic-include-template path))))
此处,在for
块内,使用namespace-set-variable-value!在名称空间的顶级环境中设置具有新标识符的关键字值,以便对于{{1}这样的关键字和值参数},模板可用的相应标识符变为(render-template ... #:foo 'bar)
(其foo
为@ Syntax
),其值为@foo
。
例如,要渲染作业概述模板,您可以执行以下操作:
bar
然后在(render-template "templates/homework-overview.html"
#:dates (sort (get-all-homework-dates) string<?))
里面你会有:
templates/homework-overview.html
但是,在使用...
@dates
...
时要小心,并考虑以下相关内容: