Compojure HTML Formatting - html

I'm relatively new to Clojure and a complete HTML/Compojure virgin. I'm trying to use Compojure to create static pages of HTML using a function similar to this:
(defn fake-write-html
[dir args]
(let [file (str dir *file-separator* *index-file*)
my-html (html
(doctype :html4)
[:html
[:head
[:title "Docs and Dirs:"]]
[:body
[:div
[:h2 "A nice title"]]
[:div
[:ul
[:li "One"]
[:li "Two"]]]]])]
(clojure.contrib.duck-streams/spit file my-html)))
The function just writes HTML to a file. (The args argument is irrelevant here. Just there to assure the example compiles and runs in my program.)
"Programming Clojure" indicated that the call to the html function would produce formatted HTML -- multiple lines with indentation. All I get is the doc type as expected followed by all of the HTML on a single line. HTML Tidy doesn't find any issues with the content of the output file. It comes out as a single line if I println it at the REPL too.
Is there something else needed to get formatted output?

The formatting of HTML output in Compojure was removed for performance and complexity reasons. To get formatted output you will probably have to write your own printer function.
I usually output HTML as Compojure sees fit and use Firebug to view it live in my browser. Firebug will display it nicely formatted no matter if it's really all on one line or not. This works well enough most of the time. If you need to serialize this HTML in a readable form, you could keep it as Clojure vectors and sexps and serialize it that way.

Although Brian's answer pointed me to Firebug, enabling the debugging I wanted, I was just to obsessive-compulsive to leave it alone. Following up on kwertii's pointer to JTidy, I included the following code in my program.
Edit: Simplified the code somewhat
(ns net.dneclark.someprogram
(:gen-class)
...
(:import (org.w3c.tidy Tidy))
)
...
(defn configure-pretty-printer
"Configure the pretty-printer (an instance of a JTidy Tidy class) to
generate output the way we want -- formatted and without sending warnings.
Return the configured pretty-printer."
[]
(doto (new Tidy)
(.setSmartIndent true)
(.setTrimEmptyElements true)
(.setShowWarnings false)
(.setQuiet true)))
(defn pretty-print-html
"Pretty-print the html and return it as a string."
[html]
(let [swrtr (new StringWriter)]
(.parse (configure-pretty-printer) (new StringReader (str html)) swrtr)
(str swrtr)))
I added the jtidy-r938.jar to my project (NetBeans using the enclojure plugin) and imported it. The configuration function tells the parser to output formatted, indented HTML and skip the warnings. The return value from the pretty-printer function is now nicely formatted whether I open it with Firebug or a simple text editor.

There are tons of HTML pretty printers available for Java, notably JTidy, a Java port of HTML Tidy. You can easily feed Clojure's output through this library programatically and get neatly indented and formatted HTML back.
HTML Tidy is also available as a command-line program for Unix if you'd care to go that route -- you can just pipe your HTML through it like any other shell program.

The above did not work for me.
I changed this a bit.
add this [jtidy "4aug2000r7-dev"] to project.clj
(:use clojure.core)
(:import (org.w3c.tidy Tidy))
(:import (java.io ByteArrayInputStream ByteArrayOutputStream)))
(defn configure-pretty-printer
"Configure the pretty-printer (an instance of a JTidy Tidy class) to
generate output the way we want -- formatted and without sending warnings.
Return the configured pretty-printer."
[]
(doto (new Tidy)
(.setSmartIndent true)
;(.setTrimEmptyElements true)
(.setShowWarnings false)
(.setQuiet true)))
(defn pretty-print-html
"Pretty-print the html and return it as a string."
[html]
(let [swrtr ( ByteArrayOutputStream.)]
(.parse (configure-pretty-printer) (ByteArrayInputStream. (.getBytes (str html))) swrtr)
(str swrtr)))

If anyone is still looking at this query, you need the hiccup library. If formats HTML from exactly the Clojure data structure shown.
So
(require '[hiccup.core :refer [html]])
(defn fake-write-html
[dir args]
(let [file (str dir *file-separator* *index-file*)
my-html (html
[:html
[:head
[:title "Docs and Dirs:"]]
[:body
[:div
[:h2 "A nice title"]]
[:div
[:ul
[:li "One"]
[:li "Two"]]]]])]
(clojure.contrib.duck-streams/spit file my-html)))
will work exactly as the original poster intended. Strongly recommended.

Related

How to auto indent multiple files?

Currently, I generate static files and those files aren't indented properly. Emacs' auto indent works great with c-x h tab, but that's per file. I want to auto indent multiple files (Like 50 or so, thus it's not feasible to do it manually).
Is there any way to accomplish this? Whether it be using a different text editor or a script or etc. If it helps, most of the files are .html.
I tested the code below with some HTML files, it works well.
(defun indent-file (file-name)
(save-window-excursion
(find-file file-name)
(indent-region (point-min) (point-max))
(write-region nil nil file-name)))
;; argv is a list stores command line option. In this case, it will be ("/your/directory/path").
;; directory-files-recursively will find files recursively, and it needs emacs 25.1 or later.
(let* ((target-dir (car argv))
(target-file-names (directory-files-recursively target-dir ".*.html$")))
(dolist (file-name target-file-names)
(indent-file file-name)))
Save the code above as 'indent-files.el'
Run emacs --script indent-files.el "/your/directory/path" in terminal
It will be tricky if you want to use emacs lisp as a common script language, although it actually could indeed. Here are some tips: https://swsnr.de/blog/2014/08/12/emacs-script-pitfalls/

not found Calls: <Anonymous> error when knitting from r studio to HTML

{r,eval=F}
corfit <- duplicateCorrelation(brain.rma, design.trt, block = blocks)
{r histOfcorrelations}
print(cor)
{r}
plot(hist(tanh(corfit$atanh.correlations)))
My codes run just fine in the RMD file, but will not knit to HTML.
Error in hist(tanh(corfit$atanh.correlations)) : object 'corfit' not
found Calls: ... withCallingHandlers -> withVisible ->
eval -> eval -> plot -> hist Execution halted
Any suggestions?
Thanks!
I think that it might be because your statement eval=F.
This in fact makes knitr not to evaluate corfit and then the object can't be found.
Try to delete eval=F and see what happens!
You need to remove your code: "eval=F"
eval = FALSE prevents code from being evaluated. (And obviously if the code is not run, no results will be generated). This is useful for displaying example code, or for disabling a large block of code without commenting each line.
https://yihui.org/knitr/options/#code-evaluation

Function argument as part of path to a file in Clojure

Suppose I have the same file name, placed in five different sub-folders. The file in question has the same name in all folders but otherwise has different values.
Suppose my file is called something like test.csv. My folder are A1,A2,A3,A4 and A5.
My data-read structure looks as so:
(defn my-data [folder]
(loop [SUB-FOLDER (str 'folder)
X []
data (with-open [file (clojure.java.io/reader "./resources/SUB-FOLDER/test.csv")]
(doall (csv/read-csv file)))]
(def row (first data))
(if (nil? row)
[(lazy-seq X)]
(recur (conj X (map #(Float/parseFloat %) row))
(rest data)))))
I would call this function as so
(def Y (map vec (get (my-data A1) 0)))
Where I am trying to access the file test.csv in the sub-folder A1 which I am passing as an argument to my csv-read function.
Now obviously the above code does not work, but it provides an overview of what I am trying to achieve.
How could one make the minimal example work?
Thanks.
Something like this should put your data from one folder into a sequence of sequences:
(defn read-data [folder]
(let [data (csv/read-csv (slurp (str "./resources/" folder "/test.csv")))]
(for [line data]
(map #(Float/parseFloat %) line))))
Change map to mapv if you want to have vectors, and wrap the for with into [] if you want a vector of vectors. This assumes folder is a string. Because your files are very small you don't need to open them with a reader, it's easier to slurp them and then parse them.
A fe issues with your original code:
You're always trying to read a file called "./resources/SUB-FOLDER/test.csv" instead of replacing the name of your folder.
You don't want to use def inside a function. See let.
Calling lazy-seq on an already realized sequence doesn't do anything.
By calling doall on your reader you're forcing all your data into memory instead of reading it and processing it as you go (that's why I replaced it with slurp). If you're going to process it in a loop as you read it, you want the with-open outside the loop (and no doall).

Clojure : missing namespace errors when running "use" at the REPL

I have a .clj file that starts like this :
(ns clojure_crawl.core)
(require '[clj-http.client :as client])
(use 'clojure.contrib.json)
Followed by several function definitions :
(defn f1 [] "" (+ 1 1))
(defn f2 [] "" (+ 2 2))
etc...
However, when I run the command "(use 'myfile.core :reload)"
Some of my functions , although visible at the REPL, cannot run do to "missing namespace" errors.
How do I add the dependencies so that the REPL can run any of the functions defined in my file ?
If your code is in "clojure_crawl/core.clj", its namespace should be clojure-crawl.core (note the hyphen). See http://clojure.org/libs
As Joost already said, you have to be careful with hyphens and underscores: wherever you use a hyphen in your namespace names, replace it with an underscore in the corresponding file/directory names (and vice versa).
Also, the use of the require and use functions in clj source files is discouraged. Instead, declare the libraries you need directly in the ns macro:
(ns clojure-crawl.core
(:require [clj-http.client :as client])
(:use clojure.contrib.json))
This also takes the burden of properly quoting the required namespaces from you.

Emacs mode to edit JSON

Does anybody know a good Emacs mode to edit JSON? An app I am working on uses a JSON based communication protocol and having the data nicely indented and syntax-highlighted would help me a lot in the process of figuring it out.
+1 for Josh's json-mode -- works well for me. I added
(defun beautify-json ()
(interactive)
(let ((b (if mark-active (min (point) (mark)) (point-min)))
(e (if mark-active (max (point) (mark)) (point-max))))
(shell-command-on-region b e
"python -m json.tool" (current-buffer) t)))
and
(define-key json-mode-map (kbd "C-c C-f") 'beautify-json)
to json-mode.el to make the shell command invocation easier.
UPDATE: For those of you with a need/desire to do this with unicode, see my question here. The upshot is rather than using:
python -m json.tool
you will want to use
python -c 'import sys,json; data=json.loads(sys.stdin.read()); print json.dumps(data,sort_keys=True,indent=4).decode("unicode_escape").encode("utf8","replace")'
This both beautifies the JSON as well as preserving the original Unicode content.
js-mode supports syntax highlighting and indentation for json files.
This is as of Emacs 23.2, when espresso-mode was incorporated into Emacs and renamed js-mode.
Check it out:
http://www.nongnu.org/espresso/
Have you tried Steve Yegge's js2-mode for Emacs?
If you want something lightweight try this major-mode I hacked together: https://github.com/joshwnj/json-mode
It's actually no more than some extra syntax highlighting on top of javascript-mode, but for my purposes I've found it to work quite well.
Another common use-case is auto-formatting a JSON file (eg. if it's whitespace-compressed and you want more readability). To do this I'm just piping the buffer through a command-line script: C-u M-|
I've prepared a workaround for js2-mode so it parses json files without errors.
You can find it in my comment: http://code.google.com/p/js2-mode/issues/detail?id=50#c7
(I wanted to post it as a comment do J.F. Sebastian solution, but it seems I'm not allowed to do so (no 'add comment' link))
json.el by Edward O'Connor is part of GNU Emacs since 23.1 (2008).
While it isn't a syntax highlighter, it has a useful function to format JSON:
M-x json-pretty-print-buffer RET
So, if you have a recent version of Emacs, there is no need for jq or python -m json.tool.
Since JSON is a subset of YAML, yaml-mode works too (I don't know how it compares to js-mode and json-mode, though).
Install (from emacs): M-x package-install yaml-mode.
Association of yaml-mode with YAML and JSON files, in ~/.emacs.d/init.el:
(add-to-list 'auto-mode-alist '("\\.yaml$" . yaml-mode))
(add-to-list 'auto-mode-alist '("\\.json$" . yaml-mode))
JSON is supported by espresso-mode
js3-mode:https://github.com/thomblake/js3-mode
js3-mode is an improved js2-mode
This package can be installed by package-list-packages command
I will also second Josh's json-mode, but also recommend flymake-json as an addition. It helps highlight syntax errors.
I don't like using python -mjson.tool because it reorders items in JSON objects.
I find (prog-indent-sexp) works just fine to reindent, and using jsonlint
instead of python -mjson.tool works for pretty printing/reformatting in beautify-json
(eval-after-load "json-mode"
'(progn
(require 'flymake-json)
;; flymake-cursor displays error in minibuffer message area instead of requiring hover
(require 'flymake-cursor)
(add-hook 'json-mode-hook 'flymake-json-load)
(define-key json-mode-map "\C-c\C-n" (function flymake-goto-next-error))
)
)
I've expanded on Mariusz Nowak's workaround, to make it usable as a major mode in its own right. Little modification was required beyond simply deriving the mode; the only change Nowak's work actually needed was the ability to recognize buffers not associated with files, or associated with files whose names don't end in .json, as JSON, which we accomplish with a buffer-local variable.
Here's the augmented workaround:
(make-variable-buffer-local 'js2-parse-as-json)
(defadvice js2-reparse (before json)
(setq js2-buffer-file-name buffer-file-name))
(ad-activate 'js2-reparse)
(defadvice js2-parse-statement (around json)
(if (and (= tt js2-LC)
js2-buffer-file-name
(or js2-parse-as-json
(string-equal (substring js2-buffer-file-name -5) ".json"))
(eq (+ (save-excursion
(goto-char (point-min))
(back-to-indentation)
(while (eolp)
(next-line)
(back-to-indentation))
(point)) 1) js2-ts-cursor))
(setq ad-return-value (js2-parse-assign-expr))
ad-do-it))
(ad-activate 'js2-parse-statement)
(define-derived-mode json-mode js2-mode "JSON"
"Major mode for editing JSON data."
:group 'json
(setq js2-parse-as-json t)
(js2-reparse t))
(add-to-list 'auto-mode-alist '("\\.json$" . json-mode))
If you already use js2-mode, this may be a better option than js-mode plus flymake-json because you need not install anything new (js2-mode already does syntax checking, no need for an external tool), and because this mode will inherit your js2-mode configuration, which js-mode will not.
I would also recommand js2-mode.
JSON stands for JavaScript Object Notation. It's not another language and it's even not a data container like yaml or xml are. JSON could be used as a data container if there's no function (or in this case we should say method) inside a JSON object, but it's not the primary goal of JSON :-)
var myJSObject = {
attr: {foo: "bar", baz: ["quux", "truc", "pouet"]},
fooAlert: function (num) {
alert(this.attr.foo+' '+num);
}
};
myJSObject.fooAlert(42);