How do I compile Clojurescript forms from within Clojure? - clojure

I am using clj-webdriver to do some Selenium based testing on a Clojurescript web app. Sometimes, there is something in the app itself that I want to be able to fiddle with while the test are running. I see that clj-webdriver has something called (execute-script js args) that takes a string of Javascript code and runs it on the current testing browser. I have tested this and it seems to work. I would like to pass clojurescript code to execute-script though. I need something that will compile my Clojure form into Clojurescript code.
I see the following question that sort of relates. It says to use the js/emit function from clutch. I searched clutch and found it mentioned only in (view) in cljs-views.clj I have attempted the following in a repl:
user> (use 'com.ashafa.clutch.cljs-views)
nil
user> view
<core$comp$fn__4034 clojure.core$comp$fn__4034#ebd3f80>
user> js/emit
CompilerException java.lang.RuntimeException: No such namespace: js, #compiling (NO_SOURCE_PATH:1)
user>
This isn't terribly surprising, how could js be in a regular clojure namesapce? But how do I use this (or any other) system to generate Clojurescript (javascript) code that I can pass to execute-script?

Use the cljs.closure/build function:
(use '[cljs.closure :only [build]])
(build '(print "hello") {:optimizations :simple :pretty-print true})
There are more examples in a comment at the bottom of closure.clj. There are options for outputting to a file as well.

Related

How to properly set a timezone in a clojure REPL?

When running a query on a postgres database on a clojure REPL, the timestamps fields are presented in UTC and I need them to be in timezone America/Sao_Paulo (UTC-3)
So far I have tried the following on Intellij's REPL:
Set -Duser.timezone=America/Sao_Paulo inside the file idea.vmoptions (intellij's)
Add :jvm-opts ["-Duser.timezone=America/Sao_Paulo"] to project.clj
Add -Duser.timezone=America/Sao_Paulo in Intellij's REPL configuration
export JAVA_OPTS="-Duser.timezone=America/Sao_Paulo:$JAVA_OPTS" inside ~/.zshrc
and the following on Leiningen REPL:
Add :jvm-opts ["-Duser.timezone=America/Sao_Paulo"] to project.clj
export JAVA_OPTS="-Duser.timezone=America/Sao_Paulo:$JAVA_OPTS" inside ~/.zshrc
None worked so far!
Sample code
(ns experiments
(:require [next.jdbc :as jdbc]))
(def db
{:dbtype "postgres"
:dbname "<dbname>"
:host "<host>"
:port 5432
:user "<user>"
:password "<pass>"})
(def ds (jdbc/get-datasource db))
(jdbc/execute! ds ["select current_timestamp"])
You did not mention any Postgres options. Please study this page carefully for info and options.
If the above does not solve your problem, it may be easiest to use java.time to do the conversion. I also have some helper/convenience functions available here. Unit tests show them in action, and the source code provides examples of java.time interop from clojure.
I would avoid the older Joda Time libraries as they are obsolete (replaced by java.time). I think that Java interop is the easiest & most straightforward way to access java.time.

Testing a CRUD Clojure functions like with ruby Rspec

I just finished my first six weeks working with Clojure and so far I'm pretty happy with the language. I'm developing my personal blog with leiningen and PostgreSQL. I already can publish new content, upload files and I have sessions, cookies and roles, anyway I think at this point I have enough code to start to worry about the testing section, but I'm kind of stuck since looks like a lot of things are happening in the clojure's testing and spec side.
So I have this function:
(defn download
"GET /admin/uploads/download/:id"
[params]
(let [id (-> params :id)
upload (model-upload/get-upload id)
filename (:filename upload)
body (clojure.java.io/file (str "public/uploads/" filename))]
{:status 200
:body body
:headers {"Content-Type" "application/pdf"
"Content-Length" (str (.length body))
"Cache-Control" "no-cache"
"Content-Disposition" (str "attachment; filename=" filename)}}))
The function takes a map as argument and delivers a final map to be sent and processed by compojure. I come from a Rails world so the way to test this function in Rails would be to create a FactoryGirl class, create a Rspec model file with the classic:
expect(first_map).to eq(map_returned_by_function)
in it comparing what is expected, and then to run the rspec from the command line to get the green or red line.
Since yesterday I'm trying to replicate that process with Clojure using this doc:
https://www.codesai.com/2018/03/kata-generating-bingo-cards
but I think there is not yet a "standard" way to do a test including the DB (CRUD) part in Clojure. I don't even know where to put the spec files. I see Clojure libraries similar to FactoryGirl but I don't know if I should create my own data structures with spec so I'm not sure where to start, there are clojure.test.check.generators and spec generators but I don't know if they are different or if I should use only spec but not clojure.test.check. Can I run a test from the command line and not inside the REPL?
I mean: is there a document or tutorial about how to test a set of CRUD functions? I think I just need the initial HOWTO and then I could take it from there and I'll write a tutorial to newbies like me.
UPDATED:
It looks like Midje is what I'm looking for:
https://github.com/marick/Midje/wiki/A-tutorial-introduction
It's idiomatic in Clojure to push IO to the edges of your application. Instead of reading from the DB inside your download function, you pass in the data read from the DB into your download function in the param map. Then you write your tests against the pure part.
Your function would end up looking like this:
(defn download-without-db
"GET /admin/uploads/download/:id"
[params]
(let [upload (-> params :upload)
filename (:filename upload)
body (clojure.java.io/file (str "public/uploads/" filename))]
{:status 200
:body body
:headers {"Content-Type" "application/pdf"
"Content-Length" (str (.length body))
"Cache-Control" "no-cache"
"Content-Disposition" (str "attachment; filename=" filename)}}))
(defn get-upload-from-db [params]
(assoc params :upload (-> params :id model-upload/get-upload)))
(defn download [params]
(-> params
get-upload-from-db
download-without-db))
You're just looking for clojure.test. It even mentions relationships with RSpec in its doc.
This is included as part of Clojure itself, no dependencies are needed, and I'd recommend you get familiar with it first before using a non standard test framework like Midje, since it is the defacto test framework for Clojure, and the most popular one.
You would write a test as such:
(deftest download
(testing "With valid input"
(testing "it should return a header map with filename included"
(is (= first_map (unit/download {:id 1}))))))
Now, Clojure is not object oriented, so there are no objects to mock. That said, you often use Java form within Clojure, and Java provides classes and objects. If you want to mock them easily, you can use the Java mocking framework called Mockito.
In your case though, the download function does not use any Java objects. So you don't need too.
Now, if you want this to be an integration test, the test I wrote is good enough for you. If you want this to be a unit test, and I assume (model-upload/get-upload id) does some IO, you'll want to mock the model-upload/get-upload function. You can easily do this using with-redefs-fn:
(deftest download
(testing "With valid input"
(testing "it should return a header map with filename included"
(with-redefs-fn {#'model-upload/get-upload (constantly {:filename "cool.pdf"})}
(is (= first_map (unit/download {:id 1})))))))
Or you can use with-redefs:
(deftest download
(with-redefs [model-upload/get-upload (constantly {:filename "cool.pdf"})]
(testing "With valid input"
(testing "it should return a header map with filename included"
(is (= first_map (unit/download {:id 1})))))))
Here are some online resources for you:
http://jafingerhut.github.io/cheatsheet/clojuredocs/cheatsheet-tiptip-cdocs-summary.html
http://clojuredocs.org/
http://clojure-doc.org/
https://www.braveclojure.com/
https://pragprog.com/book/dswdcloj2/web-development-with-clojure-second-edition
and the following is an example of how I like to structure general tests (not CRUD, though):
https://github.com/cloojure/tupelo/blob/master/test/tst/tupelo/misc.cljc

How to access db.clj methods in core.cljs in clojure

I am trying to create a web app in clojure.
i have used clojurescript om and react.
there are two files core.cljs and db.clj.
core.cljs contains ui for login page and db.clj contains all database connections.
Now i am trying to call a db.clj method add-user[username password] in
core.cljs.
In db.clj
(defn add-user [username,password]
(sql/with-connection db
(sql/insert-values :users [:username :password]
[username password])))
In core.cljs
(dom/button #js {:ref "submit"
:onClick (fn[e](add-user usname passwrd))}"submit")
But i am not able to call that method in core.cljs.
It shows some error message like
clojure.lang.ExceptionInfo : failed compiling file:src\login_page\core.cljs
clojure.lang.ExceptionInfo : No such namespace: login_page.db, could not locate login_page/db.cljs, login_page/db.cljc, or Closure namespace "login_page.db"
Rename db.clj to either db.cljs or db.cljc. That should get you past the 'No such namespace' error message.
That's the basic gist of it. Of course your dependencies on clj libraries will have to be removed - that might be the reason for the negative comment below. Alter your code so that you use a simple atom as your database. That should get you developing.
And you can wait for a much better answer than this one that will show you how to get the Client and Server communication setup. But it may not come because, as pointed out in the comments, there is already documentation for this, and unfortunately quite a few choices that have to be made. Another unfortunate thing is that the way to do it now may not be the way to do it early next year. Watch the Om-Next space!
I've never had any problems compiling .cljs or .cljc files. You just have to set up your lein project.clj file properly. There will be plenty of examples if you Google around, or you can take a look at the following small Github project: https://github.com/chrismurrph/passing-time - no need to worry about the code, just look at its project.clj file.

Clojure REPL and workflow

Coming from Haskell, my usual workflow would be to :l <file name.hs> on ghci and use the functions and ADT that I have there.
Right now I am using lein repl on a typical lein new app project context. I have created a testing.clj file next to my core.clj. There I defined a couple of functions, a protocol and a record implementing the protocol. I was able to use the function by (use 'testing.testing :reload) the problem is that I am not able to use the actual record:
(def c (Something. 0))
I get:
CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: Something
So, what would be the a "better" workflow in this case? Where I don't want to set the functions, protocols, records directly on the REPL, but also I don't want to rely on my core.cls file? I just want a file where I can dump a bunch of stuff and play with it.
PS: My env is Mac OSX Terminal + Sublime
Edit: After a couple of minutes I was able to load the record by:
(load-file <file name>)
(import 'testing.testing.Something)
I mean, for sure there is a better way than this... :/ I just want to load everything. On the other hand I am able to use the protocol methods the record implements.
Have you tried using the convenience function that is automatically defined for creating records? In this example it would be (->Something 0).
(Something. 0) is using the Java constructor, which requires importing the Java class separately. The Java class is created automatically when you define a record to allow Java interop with things you've defined in Clojure.
Using the (->Something 0) syntax is the correct way to go and should be possible after you (use 'testing.testing :reload).
Edit Given the above didn't seem to help, here's some step-by-step instructions to get a minimal working example
You have an app directory testing created with lein new app testing
In testing/src/testing you create testing.clj containing the following two lines
(ns testing.testing)
(defrecord Something [n])
Run lein repl from within your project directory
Use the namespace with (use 'testing.testing :reload)
(:n (->Something 42)) will create an instance of Something and retrieve the value of its n member - in this case 42.

Compojure Lib-Noir session/put! unbound var error

I am converting an older web app I made a few months ago from Noir to Compojure and I am using the Lib-Noir add-on. It appears that session/put! is either changed in some way I don't understand or it is bugging out for whatever reason.
Here, I can see that 4Clojure appears to be using it with no problems: See Line 51. I also found this thread that covers the same question but there doesn't appear to be a satisfactory response.
This should work (Noir):
user=> (require '[noir.session :as sesh])
nil
user=> (sesh/put! :user "me")
ClassCastException clojure.lang.Var$Unbound cannot be cast to clojure.lang.Atom
clojure.core/swap! (core.clj:2162)
The above is the same error that I am looking at on the webpage. Basically I'm stuck.
Edit to add
Appears I created a bit of confusion with the command line part: (put!) is not working in the program either. There's not much to write about it, except that it is (shesh/put! :uname user) and it appears that :uname isn't working. I'm confused as to why it would have worked before and not now when I am using the same tools as before. This is a rewrite of a site I build about 6 months ago. I'm just moving it to Compojure from Noir. The lib-noir session is, as far as I know, essentially the same as what was in Noir.
ANOTHER EDIT
I put the code up on github. This isn't the completed project, but hopefully someone can decipher what is going on here: https://github.com/dt1/SoloResume
If you run it from the REPL, there is no browser session registered in Noir. You can simulate this by using binding:
(binding [sesh/*noir-session* (atom {:somekey "somevalue"})]
(sesh/put! :user "borkdude"))
Use this only for testing/simulating to see what goes on in the session map, not in production code.
A fairly old question, but answering here as it was the first Google result when I had the same problem. I was using compojure:1.1.6, ring:1.2.1 and lib-noir:0.7.6
You need to use noir.session/wrap-noir-session when defining your app - e.g:
(def app
(-> (handler/site (routes app-routes ))
session/wrap-noir-session
wrap-base-url))
References:
https://groups.google.com/d/msg/clojure/XXgSGhF912I/luhN9wmMoi8J