2017-04-03 75 views
0

我正在寫一個使用球拍網絡服務器(需要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 

呼叫(include-template template-path)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"))))) 

不會發生錯誤。似乎球拍以某種方式要確保,有一個有效的路徑include-template。但我希望這是對該程序的價值。否則,我不能寫一個做這個工作的程序。

另外我希望提供給過程的關鍵字的值對模板可見。我不確定,如果是這種情況,或者我需要在include-template調用周圍加上某種let,因爲我無法獲得代碼以便運行,以便對其進行測試。

我該怎麼寫這樣的程序?

,因爲我想有一個理想的過程的例子:

  • 的Jinja2的render_template

我能提供任何關鍵字參數我想和渲染我希望呈現的任何模板。我也不太明白,爲什麼包括像"rm -rf /"這樣的東西可能會損壞任何東西。對我來說,似乎網絡服務器應該簡單地檢查如果文件存在與該名稱。顯然它不會存在,所以拋出一個錯誤。這應該如何導致任何不必要的損害?因此,我不理解限制什麼可以用作模板路徑到字符串(除了解決方法)之外的原因。然而,對於一個SO問題來說,這可能太過分了,應該對另一個關於「爲什麼」的問題進行討論。

+0

標題文檔中的部分[如何使用模板「動態「?](http://docs.racket-lang.org/web-server/faq.html#%28part ._。How_do_.I_use_templates__dynamically __%29)解決您的問題。 –

回答

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!,因此對於關鍵字和值參數(如(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 
... 

請小心,但是,使用eval時,和請考慮以下相關內容:

+0

我只有這個解決方案的兩個問題。其中一個是我得到的錯誤,因爲函數忽略'path:/ home/xiaolong/development/Rack/blog2/htdocs/templates/base.html',自然找不到那個文件,因爲沒有'htdocs'文件夾在我的整個項目中。這很奇怪,因爲這個答案根本不包含'htdocs',所以我不知道它突然從哪裏來。另一個問題是,我無法爲此過程提供任意關鍵字參數。當我使用'make-keyword-procedure'但仍然必須使用'let'時,我如何知道任意關鍵字參數的名稱? – Zelphir

+0

也許我必須使用這個aproach設置一個默認路徑? – Zelphir

+0

對於您的第一個問題,我無法在本地重現它。我創建了一個'templates'目錄,在這個目錄下我用一些內容存儲了'static.html',然後嘗試了'(render-template「templates/static.html」)'(在同一目錄中定義了'render-template'包含'templates'文件夾)並且它按預期工作,所以也許創建問題的問題可能位於代碼中的其他位置。 – assefamaru