Closed chr15m closed 4 years ago
Recreating this I get a different exception:
Exception in thread "main" java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Keyword
Which is coming from the markdown
output being a hiccup-seq being passed to enlive/content
which expects a string.
You could use:
(-> (html "index.template.html")
(enlive/at [:section#content] (enlive/content (markdown "README.md" :html))))
but you will get escaped html.
enlive/html-content
is for inserting html content. But that is exploding for me with
Exception in thread "main" java.lang.IllegalArgumentException: No matching clause:
at hickory.convert$hickory_to_hiccup.invokeStatic(convert.cljc:36)
at hickory.convert$hickory_to_hiccup.invoke(convert.cljc:28)
at clojure.core$map$fn__5851.invoke(core.clj:2753)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:51)
at clojure.lang.Cons.next(Cons.java:39)
at clojure.lang.RT.boundedLength(RT.java:1788)
at clojure.lang.RestFn.applyTo(RestFn.java:130)
at clojure.core$apply.invokeStatic(core.clj:669)
at clojure.core$apply.invoke(core.clj:660)
at hickory.convert$hickory_to_hiccup.invokeStatic(convert.cljc:52)
at hickory.convert$hickory_to_hiccup.invoke(convert.cljc:28)
at bootleg.utils$hickory__GT_hiccup.invokeStatic(utils.clj:51)
And that is probably a bug. Investigating...
enlive's html-content
produces a hickory structure that is missing a :type
key that hickory's converter expects to find:
bootleg -e "(convert-to {:tag :blink, :attrs nil, :content [\"FOO\"]} :hiccup)"
Fails with NPE. while:
bootleg -e "(convert-to {:type :element :tag :blink, :attrs nil, :content [\"FOO\"]} :hiccup)"
succeeds.
This will require fixing. But you can work around this conversion incompatabilty at the moment by converting to hickory-seq first, then using enlive's conversion tools to convert back to html, like:
(-> (html "index.template.html")
(convert-to :hickory-seq)
(enlive/at [:section#content] (enlive/html-content "<blink>FOO</blink>"))
net.cgrand.enlive-html/emit*
(->> (apply str)))
@retrogradeorbit will wait for the fix to html-content
. Thanks!
Once that's working it would be good to document that as a common example. Most of the examples are command line things to demonstrate functionality and reveal what is going on under the hood, whereas a user wants to see practical examples they would use. Will create a new ticket for this.
Fixed in v0.1.2
bootleg -e '(-> (html "index.template.html") (enlive/at [:section#content] (enlive/content (markdown "README.md" :html))))'
@retrogradeorbit this is still segfaulting for me:
$ bootleg -e '(-> (html "index.template.html") (enlive/at [:section#content] (enlive/content (markdown "README.md" :html))))'
Exception in thread "main" java.lang.NullPointerException
at bootleg.utils$convert_to.invokeStatic(utils.clj:166)
at bootleg.utils$convert_to.invoke(utils.clj:163)
at bootleg.namespaces$at.invokeStatic(namespaces.clj:26)
at bootleg.namespaces$at.doInvoke(namespaces.clj:16)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invokeStatic(core.clj:665)
at clojure.core$apply.invoke(core.clj:660)
at sci.impl.interpreter$do_recur_BANG_.invokeStatic(interpreter.cljc:123)
at sci.impl.interpreter$do_recur_BANG_.doInvoke(interpreter.cljc:121)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invokeStatic(core.clj:667)
at clojure.core$apply.invoke(core.clj:660)
at sci.impl.interpreter$apply_fn.invokeStatic(interpreter.cljc:132)
at sci.impl.interpreter$apply_fn.invoke(interpreter.cljc:130)
at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:306)
at sci.impl.interpreter$eval_call.invoke(interpreter.cljc:271)
at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:320)
at sci.impl.interpreter$interpret.invoke(interpreter.cljc:310)
at sci.impl.interpreter$eval_do$fn__707.invoke(interpreter.cljc:62)
at sci.impl.interpreter$eval_do.invokeStatic(interpreter.cljc:62)
at sci.impl.interpreter$eval_do.invoke(interpreter.cljc:57)
at sci.impl.interpreter$eval_string.invokeStatic(interpreter.cljc:370)
at sci.impl.interpreter$eval_string.invoke(interpreter.cljc:352)
at sci.core$eval_string.invokeStatic(core.cljc:35)
at sci.core$eval_string.invoke(core.cljc:5)
at bootleg.hiccup$process_hiccup_data.invokeStatic(hiccup.clj:54)
at bootleg.hiccup$process_hiccup_data.invoke(hiccup.clj:22)
at bootleg.core$_main.invokeStatic(core.clj:62)
at bootleg.core$_main.doInvoke(core.clj:49)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at bootleg.core.main(Unknown Source)
$ bootleg --version
Version: 0.1.2
Can you give me the md and html files you are using. Or minimal versions that recreate this problem for me to test with?
Could there be a dep call missing from the build? at bootleg.utils$convert_to.invokeStatic(utils.clj:166)
Maybe enlive has not been correctly inlined? So it would work on your local (using external library ref) but not on mine where it's not installed.
at bootleg.utils$convert_to.invokeStatic(utils.clj:166)
It will probably be another enlive/hickory incompatibility. That's my hunch. Something in your markup is exposing it.
OK. Thanks for the zipfile. You are actually getting hit by #7
v0.1.3 released. Give that a try and close this if it fixes your NPE.
$ bootleg -v
Version: 0.1.3
Traceback (same files):
$ bootleg bad.clj
Exception in thread "main" java.lang.Exception: java.lang.Character cannot be cast to clojure.lang.Named [at line 1, column 1]
at sci.impl.utils$re_throw_with_location_of_node.invokeStatic(utils.cljc:64)
at sci.impl.utils$re_throw_with_location_of_node.invoke(utils.cljc:55)
at sci.impl.interpreter$eval_do$fn__707.invoke(interpreter.cljc:64)
at sci.impl.interpreter$eval_do.invokeStatic(interpreter.cljc:62)
at sci.impl.interpreter$eval_do.invoke(interpreter.cljc:57)
at sci.impl.interpreter$eval_string.invokeStatic(interpreter.cljc:370)
at sci.impl.interpreter$eval_string.invoke(interpreter.cljc:352)
at sci.core$eval_string.invokeStatic(core.cljc:35)
at sci.core$eval_string.invoke(core.cljc:5)
at bootleg.hiccup$process_hiccup_data.invokeStatic(hiccup.clj:54)
at bootleg.hiccup$process_hiccup_data.invoke(hiccup.clj:22)
at bootleg.hiccup$process_hiccup.invokeStatic(hiccup.clj:68)
at bootleg.hiccup$process_hiccup.invoke(hiccup.clj:64)
at bootleg.core$process.invokeStatic(core.clj:34)
at bootleg.core$process.invoke(core.clj:32)
at bootleg.core$_main.invokeStatic(core.clj:66)
at bootleg.core$_main.doInvoke(core.clj:49)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at bootleg.core.main(Unknown Source)
Caused by: java.lang.ClassCastException: java.lang.Character cannot be cast to clojure.lang.Named
at clojure.core$name.invokeStatic(core.clj:1595)
at clojure.core$name.invoke(core.clj:1589)
at bootleg.utils$hiccup_seq__GT_hickory_seq.invokeStatic(utils.clj:47)
at bootleg.utils$hiccup_seq__GT_hickory_seq.invoke(utils.clj:46)
at bootleg.utils$convert_to.invokeStatic(utils.clj:142)
at bootleg.utils$convert_to.invoke(utils.clj:139)
at bootleg.namespaces$at.invokeStatic(namespaces.clj:18)
at bootleg.namespaces$at.doInvoke(namespaces.clj:16)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invokeStatic(core.clj:665)
at clojure.core$apply.invoke(core.clj:660)
at sci.impl.interpreter$do_recur_BANG_.invokeStatic(interpreter.cljc:123)
at sci.impl.interpreter$do_recur_BANG_.doInvoke(interpreter.cljc:121)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invokeStatic(core.clj:667)
at clojure.core$apply.invoke(core.clj:660)
at sci.impl.interpreter$apply_fn.invokeStatic(interpreter.cljc:132)
at sci.impl.interpreter$apply_fn.invoke(interpreter.cljc:130)
at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:306)
at sci.impl.interpreter$eval_call.invoke(interpreter.cljc:271)
at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:320)
at sci.impl.interpreter$interpret.invoke(interpreter.cljc:310)
at sci.impl.interpreter$eval_do$fn__707.invoke(interpreter.cljc:62)
... 16 more
$ bootleg -v
Version: 0.1.4
$ bootleg bad.clj
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1" name="viewport">
<title>ABC</title>
</head>
<body>
<main>
<h1>ABC</h1>
<section id="content"></section>
</main>
</body>
</html>
Ok so if I use the html version of the markdown slurp it works great:
(-> (html "t.html") (enlive/at [:section#content] (enlive/html-content (markdown "r.md" :html))))
However if I try to pull it through enlive it segfaults (see below). From my perspective this is totally fine - I can just use the enlive/html-content
. I don't think it's necessary to support every different user flow, just to make the most common ones that work simple to use.
Segfaulting version:
(-> (html "t.html") (enlive/at [:section#content] (enlive/content (markdown "r.md"))))
$ bootleg bad.clj
Exception in thread "main" java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Keyword
at clojure.lang.RT.seqFrom(RT.java:553)
at clojure.lang.RT.seq(RT.java:533)
at clojure.core$seq__5387.invokeStatic(core.clj:137)
at clojure.core$seq__5387.invoke(core.clj:137)
at net.cgrand.enlive_html$flatten_nodes_coll$flat_STAR___2231.invoke(enlive_html.clj:228)
at net.cgrand.enlive_html$flatten_nodes_coll$flat__2237$fn__2238.invoke(enlive_html.clj:233)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:51)
at clojure.lang.RT.seq(RT.java:531)
at clojure.core$seq__5387.invokeStatic(core.clj:137)
at clojure.core$map$fn__5851.invoke(core.clj:2746)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:51)
at clojure.lang.RT.seq(RT.java:531)
at clojure.core$seq__5387.invokeStatic(core.clj:137)
at clojure.core$dorun.invokeStatic(core.clj:3133)
at clojure.core$doall.invokeStatic(core.clj:3148)
at clojure.walk$walk.invokeStatic(walk.clj:47)
at clojure.walk$postwalk.invokeStatic(walk.clj:53)
at clojure.walk$postwalk.invoke(walk.clj:53)
at clojure.core$partial$fn__5824.invoke(core.clj:2624)
at clojure.walk$walk.invokeStatic(walk.clj:46)
at clojure.walk$postwalk.invokeStatic(walk.clj:53)
at clojure.walk$postwalk.invoke(walk.clj:53)
at clojure.core$partial$fn__5824.invoke(core.clj:2624)
at clojure.core$map$fn__5851.invoke(core.clj:2755)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:51)
at clojure.lang.Cons.next(Cons.java:39)
at clojure.lang.RT.next(RT.java:709)
at clojure.core$next__5371.invokeStatic(core.clj:64)
at clojure.core.protocols$fn__8144.invokeStatic(protocols.clj:169)
at clojure.core.protocols$fn__8144.invoke(protocols.clj:124)
at clojure.core.protocols$fn__8099$G__8094__8108.invoke(protocols.clj:19)
at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:31)
at clojure.core.protocols$fn__8131.invokeStatic(protocols.clj:75)
at clojure.core.protocols$fn__8131.invoke(protocols.clj:75)
at clojure.core.protocols$fn__8073$G__8068__8086.invoke(protocols.clj:13)
at clojure.core$reduce.invokeStatic(core.clj:6828)
at clojure.core$into.invokeStatic(core.clj:6895)
at clojure.walk$walk.invokeStatic(walk.clj:50)
at clojure.walk$postwalk.invokeStatic(walk.clj:53)
at clojure.walk$postwalk.invoke(walk.clj:53)
at clojure.core$partial$fn__5824.invoke(core.clj:2624)
at clojure.core$map$fn__5851.invoke(core.clj:2753)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:51)
at clojure.lang.RT.seq(RT.java:531)
at clojure.core$seq__5387.invokeStatic(core.clj:137)
at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:24)
at clojure.core.protocols$fn__8131.invokeStatic(protocols.clj:75)
at clojure.core.protocols$fn__8131.invoke(protocols.clj:75)
at clojure.core.protocols$fn__8073$G__8068__8086.invoke(protocols.clj:13)
at clojure.core$reduce.invokeStatic(core.clj:6828)
at clojure.core$into.invokeStatic(core.clj:6895)
at clojure.walk$walk.invokeStatic(walk.clj:50)
at clojure.walk$postwalk.invokeStatic(walk.clj:53)
at clojure.walk$postwalk.invoke(walk.clj:53)
at clojure.core$partial$fn__5824.invoke(core.clj:2624)
at clojure.walk$walk.invokeStatic(walk.clj:46)
at clojure.walk$postwalk.invokeStatic(walk.clj:53)
at clojure.walk$postwalk.invoke(walk.clj:53)
at clojure.core$partial$fn__5824.invoke(core.clj:2624)
at clojure.core$map$fn__5851.invoke(core.clj:2755)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:51)
at clojure.lang.Cons.next(Cons.java:39)
at clojure.lang.RT.next(RT.java:709)
at clojure.core$next__5371.invokeStatic(core.clj:64)
at clojure.core.protocols$fn__8144.invokeStatic(protocols.clj:169)
at clojure.core.protocols$fn__8144.invoke(protocols.clj:124)
at clojure.core.protocols$fn__8099$G__8094__8108.invoke(protocols.clj:19)
at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:31)
at clojure.core.protocols$fn__8131.invokeStatic(protocols.clj:75)
at clojure.core.protocols$fn__8131.invoke(protocols.clj:75)
at clojure.core.protocols$fn__8073$G__8068__8086.invoke(protocols.clj:13)
at clojure.core$reduce.invokeStatic(core.clj:6828)
at clojure.core$into.invokeStatic(core.clj:6895)
at clojure.walk$walk.invokeStatic(walk.clj:50)
at clojure.walk$postwalk.invokeStatic(walk.clj:53)
at clojure.walk$postwalk.invoke(walk.clj:53)
at clojure.core$partial$fn__5824.invoke(core.clj:2624)
at clojure.core$map$fn__5851.invoke(core.clj:2753)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:51)
at clojure.lang.RT.seq(RT.java:531)
at clojure.core$seq__5387.invokeStatic(core.clj:137)
at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:24)
at clojure.core.protocols$fn__8131.invokeStatic(protocols.clj:75)
at clojure.core.protocols$fn__8131.invoke(protocols.clj:75)
at clojure.core.protocols$fn__8073$G__8068__8086.invoke(protocols.clj:13)
at clojure.core$reduce.invokeStatic(core.clj:6828)
at clojure.core$into.invokeStatic(core.clj:6895)
at clojure.walk$walk.invokeStatic(walk.clj:50)
at clojure.walk$postwalk.invokeStatic(walk.clj:53)
at clojure.walk$postwalk.invoke(walk.clj:53)
at clojure.core$partial$fn__5824.invoke(core.clj:2624)
at clojure.walk$walk.invokeStatic(walk.clj:46)
at clojure.walk$postwalk.invokeStatic(walk.clj:53)
at clojure.walk$postwalk.invoke(walk.clj:53)
at clojure.core$partial$fn__5824.invoke(core.clj:2624)
at clojure.core$map$fn__5851.invoke(core.clj:2755)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:51)
at clojure.lang.Cons.next(Cons.java:39)
at clojure.lang.RT.next(RT.java:709)
at clojure.core$next__5371.invokeStatic(core.clj:64)
at clojure.core.protocols$fn__8144.invokeStatic(protocols.clj:169)
at clojure.core.protocols$fn__8144.invoke(protocols.clj:124)
at clojure.core.protocols$fn__8099$G__8094__8108.invoke(protocols.clj:19)
at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:31)
at clojure.core.protocols$fn__8131.invokeStatic(protocols.clj:75)
at clojure.core.protocols$fn__8131.invoke(protocols.clj:75)
at clojure.core.protocols$fn__8073$G__8068__8086.invoke(protocols.clj:13)
at clojure.core$reduce.invokeStatic(core.clj:6828)
at clojure.core$into.invokeStatic(core.clj:6895)
at clojure.walk$walk.invokeStatic(walk.clj:50)
at clojure.walk$postwalk.invokeStatic(walk.clj:53)
at clojure.walk$postwalk.invoke(walk.clj:53)
at clojure.core$partial$fn__5824.invoke(core.clj:2624)
at clojure.core$map$fn__5851.invoke(core.clj:2753)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:51)
at clojure.lang.RT.seq(RT.java:531)
at clojure.core$seq__5387.invokeStatic(core.clj:137)
at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:24)
at clojure.core.protocols$fn__8131.invokeStatic(protocols.clj:75)
at clojure.core.protocols$fn__8131.invoke(protocols.clj:75)
at clojure.core.protocols$fn__8073$G__8068__8086.invoke(protocols.clj:13)
at clojure.core$reduce.invokeStatic(core.clj:6828)
at clojure.core$into.invokeStatic(core.clj:6895)
at clojure.walk$walk.invokeStatic(walk.clj:50)
at clojure.walk$postwalk.invokeStatic(walk.clj:53)
at clojure.walk$postwalk.invoke(walk.clj:53)
at clojure.core$partial$fn__5824.invoke(core.clj:2624)
at clojure.walk$walk.invokeStatic(walk.clj:46)
at clojure.walk$postwalk.invokeStatic(walk.clj:53)
at clojure.walk$postwalk.invoke(walk.clj:53)
at clojure.core$partial$fn__5824.invoke(core.clj:2624)
at clojure.core$map$fn__5851.invoke(core.clj:2755)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:51)
at clojure.lang.Cons.next(Cons.java:39)
at clojure.lang.RT.next(RT.java:709)
at clojure.core$next__5371.invokeStatic(core.clj:64)
at clojure.core.protocols$fn__8144.invokeStatic(protocols.clj:169)
at clojure.core.protocols$fn__8144.invoke(protocols.clj:124)
at clojure.core.protocols$fn__8099$G__8094__8108.invoke(protocols.clj:19)
at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:31)
at clojure.core.protocols$fn__8131.invokeStatic(protocols.clj:75)
at clojure.core.protocols$fn__8131.invoke(protocols.clj:75)
at clojure.core.protocols$fn__8073$G__8068__8086.invoke(protocols.clj:13)
at clojure.core$reduce.invokeStatic(core.clj:6828)
at clojure.core$into.invokeStatic(core.clj:6895)
at clojure.walk$walk.invokeStatic(walk.clj:50)
at clojure.walk$postwalk.invokeStatic(walk.clj:53)
at clojure.walk$postwalk.invoke(walk.clj:53)
at bootleg.utils$munge_hickory_tags.invokeStatic(utils.clj:56)
at bootleg.utils$munge_hickory_tags.invoke(utils.clj:55)
at bootleg.utils$hickory__GT_hiccup.invokeStatic(utils.clj:106)
at bootleg.utils$hickory__GT_hiccup.invoke(utils.clj:103)
at clojure.core$map$fn__5851.invoke(core.clj:2753)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:51)
at clojure.lang.RT.seq(RT.java:531)
at clojure.core$seq__5387.invokeStatic(core.clj:137)
at clojure.core$map$fn__5851.invoke(core.clj:2746)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:51)
at clojure.lang.RT.seq(RT.java:531)
at clojure.core$seq__5387.invokeStatic(core.clj:137)
at clojure.core$dorun.invokeStatic(core.clj:3133)
at clojure.core$doall.invokeStatic(core.clj:3148)
at clojure.walk$walk.invokeStatic(walk.clj:47)
at clojure.walk$postwalk.invokeStatic(walk.clj:53)
at clojure.walk$postwalk.invoke(walk.clj:53)
at bootleg.hiccup$process_hiccup_data.invokeStatic(hiccup.clj:62)
at bootleg.hiccup$process_hiccup_data.invoke(hiccup.clj:22)
at bootleg.hiccup$process_hiccup.invokeStatic(hiccup.clj:68)
at bootleg.hiccup$process_hiccup.invoke(hiccup.clj:64)
at bootleg.core$process.invokeStatic(core.clj:34)
at bootleg.core$process.invoke(core.clj:32)
at bootleg.core$_main.invokeStatic(core.clj:66)
at bootleg.core$_main.doInvoke(core.clj:49)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at bootleg.core.main(Unknown Source)
What is happening here is (markdown "r.md")
returns a hiccup-seq by default. enlive knows nothing about hiccup. And html-content
is expecting arguments of strings or hickory structures.
content
doesn't work because it flattens the nodes? https://github.com/cgrand/enlive/blob/master/src/net/cgrand/enlive_html.clj#L641
html-content
applies snippet processing across each argument: https://github.com/cgrand/enlive/blob/master/src/net/cgrand/enlive_html.clj#L658
To return the markdown as html for embedding use the :html
option. ie. (markdown "r.md" :html)
content
may work if you pass in :hickory-seq
too... maybe. Not sure if enlive will accept a sequence. Might expect a series of args of hickory. If :hickory-seq
doesn't work you could try a (apply content (markdown "r.md" :hickory-seq))
Check the enlive documentation for more info.
There are always going to be these conversions when mixing different templating frameworks and processors.
I would like better automatic conversions and error reporting. But I still have to think about how to implement them. Use :html
for now.
$ cat bad.clj
(-> (html "t.html")
(enlive/at [:section#content] (enlive/html-content (markdown "r.md" :html))))
$ bootleg bad.clj
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1" name="viewport">
<title>ABC</title>
</head>
<body>
<main>
<h1>ABC</h1>
<section id="content"><p>HELLO.</p></section>
</main>
</body>
</html>
$ cat bad.clj
(-> (html "t.html")
(enlive/at [:section#content] (apply enlive/content (markdown "r.md" :hickory-seq))))
$ bootleg bad.clj
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1" name="viewport">
<title>ABC</title>
</head>
<body>
<main>
<h1>ABC</h1>
<section id="content"><p>HELLO.</p></section>
</main>
</body>
</html>
btw, you can see what something returns like:
$ bootleg -d -e '(markdown "r.md")'
([:p {} "HELLO."])
$ bootleg -d -e '(markdown "r.md" :hickory)'
{:type :element, :attrs nil, :tag :p, :content ["HELLO."]}
$ bootleg -d -e '(markdown "r.md" :hickory-seq)'
({:type :element, :attrs nil, :tag :p, :content ["HELLO."]})
I would just make clear in the documentation that if you want to push it through enlive it needs to come out as hickory.
Will add that to the docs.
There's additional complexity here too. Because this test markdown is only one line. But if it was many lines, you'd get a sequence of hickory. If you returned :hickory
you'd only get the last form. Which is technically correct, but you know someone is going to be really confused by that at some point.
eg
$ cat r.md
# HEADING
This is some markdown with multiple forms
ok?
$ bootleg -d -e '(markdown "r.md" :hickory)'
{:type :element, :attrs nil, :tag :p, :content ["ok?"]}
$ cat bad.clj
(-> (html "t.html")
(enlive/at [:section#content] (enlive/content (markdown "r.md" :hickory))))
$ bootleg bad.clj
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1" name="viewport">
<title>ABC</title>
</head>
<body>
<main>
<h1>ABC</h1>
<section id="content"><p>ok?</p></section>
</main>
</body>
</html>
That is going to confuse someone at some point
Yes it will.
My present thought is to print to stderr a big red "WARNING: markup forms lost!" whenever a lossy conversion is done and data is lost. Your thoughts on this? Any better ideas?
Could you make markdown
just always return a seq?
As a user building a static site I don't want to have to care about these details. I generally want everything to work as strings. So have markdown come in and turn into an HTML string and get inserted into the document.
Because you've included the possibility to get the hiccup form that introduces a second way of working which is with Clojure data structures. Again though I don't want to know all the details about what particular kind of structure it is - I just want to plug stuff together like lego bricks.
I would say wherever possible don't expose gnarly edges to the user and just do what you think they would expect in the most common use-case, then give them options where they can get super technical if they want. Sensible defaults.
Sorry, I know that introduces a lot of complexity under the hood but I'm just speaking as a dumb user who simply wants to build a static site quickly and efficiently without learning too much new stuff.
I guess what I want is wrapped versions of the enlive fns which take Hiccup not Hickory. The latter format is confusing to me as an end user.
Or maybe something like enliven
would be sufficient:
(-> (html "t.html")
(enlive/at [:section#content] (enlive/content (enliven (markdown "r.md")))))
As long as there is some simple rule I need to follow when working with enlive.
I guess what I am saying is :hickory-seq
and :hickory
is one option too many. Just make it :hickory
and always return a seq, even if there is only one element.
Could you make
markdown
just always return a seq?As a user building a static site I don't want to have to care about these details. I generally want everything to work as strings. So have markdown come in and turn into an HTML string and get inserted into the document.
I know what you are saying, but this is not completely true. Initially you wanted hiccup. Now strings.
Because you've included the possibility to get the hiccup form that introduces a second way of working which is with Clojure data structures. Again though I don't want to know all the details about what particular kind of structure it is - I just want to plug stuff together like lego bricks.
It needs a default. Is that hiccup? or strings?
I would say wherever possible don't expose gnarly edges to the user and just do what you think they would expect in the most common use-case, then give them options where they can get super technical if they want. Sensible defaults.
That's what I've done. I've picked a sequence of hiccup as the default. So you can go [:div (markdown "mine.md")]
. If strings were default, this would not work. You'd get a big encoded html string as content.
Sorry, I know that introduces a lot of complexity under the hood but I'm just speaking as a dumb user who simply wants to build a static site quickly and efficiently without learning too much new stuff.
It does. It's actually complecting things together. You are asking for an easy, complex solution.
I guess what I want is wrapped versions of the enlive fns which take Hiccup not Hickory. The latter format is confusing to me as an end user.
I agree with this and I plan to do it at some point. This just requires writing auto coercing binding fuctions that wrap every enlive call. It's just a lot of work. I've done it for the at
function (which is why you can pass hiccup to at
and it doesnt blow up) but that is all. This will be done in time.
I guess what I am saying is
:hickory-seq
and:hickory
is one option too many. Just make it:hickory
and always return a seq, even if there is only one element.
I also thought about that naming. And while that will help the users who have never used hickory before, it will totally confuse those who have used hickory. As they try and use their standard (maybe preexisting) hickory code and it all blows up, because it's not actually hickory. It's a sequence of hickory.
It all stems from the underlying problem that both hiccup and hickory were never intended to hold template snippets. They were intended to contain a single, well formed HTML node.
You are asking for an easy, complex solution.
So a typical user in other words. ;)
It needs a default. Is that hiccup?
Yep I think so.
What you have working already is perfectly sufficient already. I can merge HTML, Markdown, and JSON into a nice Hiccup form. :+1:
I'll close this as it resolves the NPE exception (which were type conversion bugs). Opened three enhancement issues to improve the situation at a later date.
I'm probably doing something dumb here.
site.clj
README.md
is a standard markdown.index.template.html
is a standard HTML file with<section id="content"></section>
in it.Exception