From 0831c2e03a60ad93cf711415a6c2f2c5c3057e4a Mon Sep 17 00:00:00 2001 From: Brent Hagany Date: Sat, 3 Dec 2016 13:41:04 -0600 Subject: [PATCH 1/5] Refactor and abstract rendering with `render-pre-wrap` This is a subset of the changes in #109 that seemed to get the most positive response. It's almost purely a refactor intended to make rendering more pluggable. The only new feature is the addition of tracing to (aka `:io.perun/trace` metadata) `render` and `collection`. --- src/io/perun.clj | 145 ++++++++++++++++++++++++++++++----------------- 1 file changed, 94 insertions(+), 51 deletions(-) diff --git a/src/io/perun.clj b/src/io/perun.clj index febe1b4b..2179ba8c 100644 --- a/src/io/perun.clj +++ b/src/io/perun.clj @@ -419,6 +419,45 @@ (def render-pod (delay (create-pod' render-deps))) +(defn render-to-paths + "Renders paths in `data`, using `renderer` in `pod`, and writes + the result to `tmp`. + + `data` should be a map with keys that are fileset paths, and + values that are themselves maps with these keys: + - `:render-data` the map argument that `renderer` will be called with + - `:entry` the metadata for the item being rendered + + All `:entry`s will be returned, after having their `:content` set to the + rendering result" + [data renderer tmp tracer] + (pod/with-call-in @render-pod + (io.perun.render/update!)) + (doall + (trace tracer + (for [[path {:keys [render-data entry]}] data] + (let [content (render-in-pod @render-pod renderer render-data)] + (perun/create-file tmp path content) + (assoc entry :content content)))))) + +(defn render-pre-wrap + "Handles common rendering task orchestration + + `render-paths-fn` takes two arguments: a fileset, and a map of task options. + `options` is a map that must have a `:renderer` key, and any other keys + that are required by `render-paths-fn`. + + Returns a boot `with-pre-wrap` result" + [render-paths-fn options tracer] + (let [tmp (boot/tmp-dir!)] + (boot/with-pre-wrap fileset + (let [new-metadata (-> fileset + (render-paths-fn options) + (render-to-paths (:renderer options) tmp tracer))] + (-> fileset + (perun/merge-meta new-metadata) + (commit tmp)))))) + (deftask render "Render individual pages for entries in perun data. @@ -439,36 +478,60 @@ _ filterer FILTER code "predicate to use for selecting entries (default: `:content`)" r renderer RENDERER sym "page renderer (fully qualified symbol which resolves to a function)" m meta META edn "metadata to set on each entry"] - (let [tmp (boot/tmp-dir!) - options (merge +render-defaults+ *opts*)] - (boot/with-pre-wrap fileset - (pod/with-call-in @render-pod - (io.perun.render/update!)) - (let [files (filter (:filterer options) (perun/get-meta fileset)) - updated-files (doall - (for [{:keys [path] :as file} files] - (let [entry (merge meta file) + (let [options (merge +render-defaults+ *opts*)] + (letfn [(render-paths [fileset options] + (let [entries (filter (:filterer options) (perun/get-meta fileset)) + paths (reduce + (fn [result {:keys [path] :as entry*}] + (let [entry (merge meta entry*) render-data {:meta (perun/get-global-meta fileset) - :entries (vec files) + :entries (vec entries) :entry entry} - html (render-in-pod @render-pod renderer render-data) page-filepath (perun/create-filepath (:out-dir options) ; If permalink ends in slash, append index.html as filename - (or (some-> (:permalink file) + (or (some-> (:permalink entry) (string/replace #"/$" "/index.html") perun/url-to-path) (string/replace path #"(?i).[a-z]+$" ".html")))] (perun/report-debug "render" "rendered page for path" path) - (perun/create-file tmp page-filepath html) - entry)))] - (perun/report-info "render" "rendered %s pages" (count files)) - (perun/merge-meta (commit fileset tmp) updated-files))))) + (assoc result page-filepath {:render-data render-data + :entry entry}))) + {} + entries)] + (perun/report-info "render" "rendered %s pages" (count paths)) + paths))] + (render-pre-wrap render-paths options :io.perun/render)))) + +(defn- grouped-paths + "Produces path maps of the shape required by `render-to-paths`, based + on the provided `fileset` and `options`." + [task-name fileset options] + (let [global-meta (perun/get-global-meta fileset) + grouper (:grouper options)] + (->> fileset + perun/get-meta + (filter (:filterer options)) + grouper + (reduce + (fn [result [path {:keys [entries group-meta]}]] + (let [sorted (sort-by (:sortby options) (:comparator options) entries) + page-filepath (perun/create-filepath (:out-dir options) path) + new-entry (merge {:path page-filepath + :canonical-url (str (:base-url global-meta) path) + :date-build (:date-build global-meta)} + group-meta) + render-data {:meta global-meta + :entry new-entry + :entries (vec sorted)}] + (perun/report-info task-name (str "rendered " task-name " " path)) + (assoc result page-filepath {:render-data render-data + :entry new-entry}))) + {})))) (def ^:private +collection-defaults+ {:out-dir "public" :filterer :content - :groupby (fn [data] "index.html") :sortby (fn [file] (:date-published file)) :comparator (fn [i1 i2] (compare i2 i1))}) @@ -492,50 +555,30 @@ c comparator COMPARATOR code "sort by comparator function" p page PAGE str "collection result page path" m meta META edn "metadata to set on each collection entry"] - (let [tmp (boot/tmp-dir!) - options (merge +collection-defaults+ *opts* (if-let [p (:page *opts*)] - {:groupby (fn [_] p)}))] + (let [options (merge +collection-defaults+ + (dissoc *opts* :page) + (if-let [p (:page *opts*)] + {:grouper #(-> {p {:entries %}})} + (if-let [gb (:groupby *opts*)] + {:grouper #(->> % + (group-by gb) + (map (fn [[page entries]] + [page {:entries entries}])) + (into {}))} + {:grouper #(-> {"index.html" {:entries %}})})))] (cond (not (fn? (:comparator options))) (u/fail "collection task :comparator option should implement IFn\n") (not (ifn? (:filterer options))) (u/fail "collection task :filterer option value should implement IFn\n") (and (:page options) (:groupby *opts*)) (u/fail "using the :page option will render any :groupby option setting effectless\n") - (not (ifn? (:groupby options))) + (and (:groupby options) (not (ifn? (:groupby options)))) (u/fail "collection task :groupby option value should implement IFn\n") (not (ifn? (:sortby options))) (u/fail "collection task :sortby option value should implement IFn\n") :else - (boot/with-pre-wrap fileset - (pod/with-call-in @render-pod - (io.perun.render/update!)) - - (let [files (perun/get-meta fileset) - filtered-files (filter (:filterer options) files) - grouped-files (group-by (:groupby options) filtered-files) - global-meta (perun/get-global-meta fileset) - new-files (doall - (map - (fn [[page page-files]] - (do - (let [sorted (sort-by (:sortby options) (:comparator options) page-files) - render-data {:meta global-meta - :entries (vec sorted)} - html (render-in-pod @render-pod renderer render-data) - page-filepath (perun/create-filepath (:out-dir options) page) - new-entry (merge - meta - {:path page-filepath - :canonical-url (str (:base-url global-meta) page) - :content html - :date-build (:date-build global-meta)})] - (perun/create-file tmp page-filepath html) - (perun/report-info "collection" "rendered collection %s" page) - new-entry))) - grouped-files)) - updated-files (apply conj files (trace :io.perun/collection new-files)) - updated-fileset (perun/set-meta fileset updated-files)] - (commit updated-fileset tmp)))))) + (let [collection-paths (partial grouped-paths "collection")] + (render-pre-wrap collection-paths options :io.perun/collection))))) (deftask inject-scripts "Inject JavaScript scripts into html files. From 806011ae20c8ab3f1856a3636fc8366e6d48147b Mon Sep 17 00:00:00 2001 From: Brent Hagany Date: Sat, 3 Dec 2016 13:52:01 -0600 Subject: [PATCH 2/5] Correct error message --- src/io/perun.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io/perun.clj b/src/io/perun.clj index 2179ba8c..7728cd2a 100644 --- a/src/io/perun.clj +++ b/src/io/perun.clj @@ -567,7 +567,7 @@ (into {}))} {:grouper #(-> {"index.html" {:entries %}})})))] (cond (not (fn? (:comparator options))) - (u/fail "collection task :comparator option should implement IFn\n") + (u/fail "collection task :comparator option should implement Fn\n") (not (ifn? (:filterer options))) (u/fail "collection task :filterer option value should implement IFn\n") (and (:page options) (:groupby *opts*)) From 296065d326f6e798fc48326be251e50d071a40a7 Mon Sep 17 00:00:00 2001 From: Brent Hagany Date: Sat, 3 Dec 2016 23:50:27 -0600 Subject: [PATCH 3/5] Correct order of fileset operations, so that metadata actually gets set --- src/io/perun.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/io/perun.clj b/src/io/perun.clj index 7728cd2a..e14594e0 100644 --- a/src/io/perun.clj +++ b/src/io/perun.clj @@ -455,8 +455,8 @@ (render-paths-fn options) (render-to-paths (:renderer options) tmp tracer))] (-> fileset - (perun/merge-meta new-metadata) - (commit tmp)))))) + (commit tmp) + (perun/merge-meta new-metadata)))))) (deftask render "Render individual pages for entries in perun data. From 68e00fc1ef74241e0e4da6c738b5a0547967668b Mon Sep 17 00:00:00 2001 From: Brent Hagany Date: Sun, 4 Dec 2016 16:16:01 -0600 Subject: [PATCH 4/5] Pass task meta for `collection` through to `render-pre-wrap` --- src/io/perun.clj | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/io/perun.clj b/src/io/perun.clj index e14594e0..06ec127b 100644 --- a/src/io/perun.clj +++ b/src/io/perun.clj @@ -558,14 +558,17 @@ (let [options (merge +collection-defaults+ (dissoc *opts* :page) (if-let [p (:page *opts*)] - {:grouper #(-> {p {:entries %}})} + {:grouper #(-> {p {:entries % + :group-meta (:meta *opts*)}})} (if-let [gb (:groupby *opts*)] {:grouper #(->> % (group-by gb) (map (fn [[page entries]] - [page {:entries entries}])) + [page {:entries entries + :group-meta (:meta *opts*)}])) (into {}))} - {:grouper #(-> {"index.html" {:entries %}})})))] + {:grouper #(-> {"index.html" {:entries % + :group-meta (:meta *opts*)}})})))] (cond (not (fn? (:comparator options))) (u/fail "collection task :comparator option should implement Fn\n") (not (ifn? (:filterer options))) From 582bcc980733995d1f2d3aefc27117801003e758 Mon Sep 17 00:00:00 2001 From: Brent Hagany Date: Tue, 27 Dec 2016 18:49:26 -0600 Subject: [PATCH 5/5] Commit accidentally unstaged changes --- src/io/perun.clj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/io/perun.clj b/src/io/perun.clj index c6798f25..bf7cd0e7 100644 --- a/src/io/perun.clj +++ b/src/io/perun.clj @@ -463,7 +463,7 @@ (render-to-paths (:renderer options) tmp tracer))] (-> fileset (commit tmp) - (perun/merge-meta new-metadata)))))) + (pm/merge-meta new-metadata)))))) (deftask render "Render individual pages for entries in perun data. @@ -487,11 +487,11 @@ m meta META edn "metadata to set on each entry"] (let [options (merge +render-defaults+ *opts*)] (letfn [(render-paths [fileset options] - (let [entries (filter (:filterer options) (perun/get-meta fileset)) + (let [entries (filter (:filterer options) (pm/get-meta fileset)) paths (reduce (fn [result {:keys [path] :as entry*}] (let [entry (merge meta entry*) - render-data {:meta (perun/get-global-meta fileset) + render-data {:meta (pm/get-global-meta fileset) :entries (vec entries) :entry entry} page-filepath (perun/create-filepath @@ -514,10 +514,10 @@ "Produces path maps of the shape required by `render-to-paths`, based on the provided `fileset` and `options`." [task-name fileset options] - (let [global-meta (perun/get-global-meta fileset) + (let [global-meta (pm/get-global-meta fileset) grouper (:grouper options)] (->> fileset - perun/get-meta + pm/get-meta (filter (:filterer options)) grouper (reduce