1

I have a home page being rendered that requests user-input as vectors of integers. I need those data-structures, because they play nice with the math functions that I will use to manipulate the input:

(defn home [& [weights grades error]]
  (html
    ;; ...
   (form-to [:post "/"]
    ;; ...
    (text-area {:rows 15 :cols 30 :placeholder
"[89 78 63]
                    [78 91 60]
                    [87 65 79]
                    ..." } "grades" grades)]
     (submit-button "process"))]))

And the "process" button sends the input through a defroutes function, using a POST method, which calls a processed method that renders html showing calculated results from the input. The function being used to calculate the final list of grades is called process-grades. I am trying to use read-string to change the input data-structures into something that my function can handle, but cannot make it work. When I replace the call to processed with "TEST", I have no trouble rendering the text after hitting the process button:

(defn process-grades 
  "Takes user input from home's form-to function and processes it into the final grades list"
  [weights grades]
(->> grades
     (map (partial percentify-vector weights))
     (mapv #(apply + %))))

(defn processed [weights grades]
  (cond
   (empty? weights)
   (home weights grades "You forgot to add the weights!")
   (empty? grades)
   (home weights grades "You forgot to add the grades!")
  :else
  (do
  (html  
   [:h2 "These are your final grades."]
   [:hr]
   [:p (process-grades (read-string weights)(read-string grades))])))) ;; <- This is not working!


(defroutes grade-routes
           (GET "/" []
                {:status 200
                 :headers {"Content-Type" "text/html"}
                 :body (home)
                 })
           (POST "/" [weights grades] (processed weights grades))
           (ANY "*" []
                (route/not-found (slurp (io/resource "404.html")))))

I have done a bit of research on the html form tag, Clojure's read-string function and various ways of scripting the functionality that I need. With a glut of information I am still left wondering: what is the simplest, most concise, idiomatic way to do this? Should I reach for Clojurescript or can I use Vanilla-flavored, JVM Clojure here?

artem
  • 46,476
  • 8
  • 74
  • 78
kurofune
  • 1,055
  • 12
  • 26
  • I'd recommend using `clojure.edn/read-string` here because your data is coming from an untrusted source (user input). Using core/read-string could cause arbitrary code evaluation. – Daniel Neal Feb 27 '14 at 10:18
  • So does this mean I can add the functionality without using a scripting language? And let's say I do use Clojurescript from another name-space, will `clojure.edn/read-string` work in those functions too? I am really new to all of this, so I apologize if my questions are naive. – kurofune Feb 27 '14 at 10:29
  • No worries - yep I'm pretty sure there's no need for a scripting language here. Just send the POST data to the server, and then parse using `clojure.edn/read-string` on the server. What error are you getting at the moment? – Daniel Neal Feb 27 '14 at 10:38
  • One thing I noticed is that your sample input is a collection of vectors `[1 2 3] [4 5 6] [7 8 9]`, which may lead to undesired results because `read-string` only reads a single object from a string. – Daniel Neal Feb 27 '14 at 10:44
  • I am getting a 500 error from a wrapper that is defined under my defroutes when I try it without the clojure.edn/read-string modification, and the server doesn't start when I do use clojure.edn, throwing `java.lang.ClassNotFoundException: clojure.edn` in my terminal. Do I need to add an extra dependency or something? – kurofune Feb 27 '14 at 10:52
  • I already thought about that and even tried entering a single vector of vectors by hand into the browser input region, which is the exact form that the functions are supposed to take. e.g.: [[34.5 45.7 56.4] [71.0 82.7 93.5] [98.0 87 76] [67 78 56]]. I put this in quotations too and tested it with read-string in the repl to make sure it returned the desired structure. – kurofune Feb 27 '14 at 10:55
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/48563/discussion-between-daniel-neal-and-kurofune) – Daniel Neal Feb 27 '14 at 10:55

1 Answers1

1

You're getting an error because (process-grades) is returning a vector of numbers, which means that the form below

[:p (process-grades (read-string weights) (read-string grades))]

will end up looking like the following (once process-grades has returned):

[:p [4/5 3/2 6/3 ... more numbers]]

Hiccup only knows how to handle keyword html tags at the beginning of each hiccup vector, so it will complain about this loudly.

Eventually you'll need to format the output nicely in the way you want, but for the time being you should be able to get it running by wrapping the (process-grades ...) call in (apply str) to turn the vector into a string.

Daniel Neal
  • 4,165
  • 2
  • 20
  • 34