Global flag to turn on/off validation in Prismatic/Schema? - clojure

During development I would like to enable validation for all functions that are defined with schema.core/defn, instead of having to annotate them with :^:always-validate. Is this possible with this library?
Something like this doesn't work, probably because meta-data is only added during compile-time:
(def dev false)
;; example of schema validation
(sm/defn ^{:always-validate dev}
add :- s/Num
[a :- s/Num b :- s/Num]
(+ a b))

This seems to do what I want:
(s/set-fn-validation! false)

Related

Conditionally adding to a collection

I want to add something to a collection based on a condition and leave it alone otherwise.
I found myself writing something like this:
(defn make-zoo
[zoo has-ice]
(let [zoo (if has-ice (conj zoo "penguins") zoo)]
zoo))
(make-zoo ["tigers"] false) ;["tigers"]
(make-zoo ["polar bears"] true) ;["polar bears" "penguins"]
I'm pretty new to Clojure, but this seems like a clunky solution for a common operation. Is there a more elegant way to address this?
We can simplify make-zoo using the cond-> macro, a conditional derivative of the -> threading macro:
(defn make-zoo [zoo has-ice]
(cond-> zoo, has-ice (conj "penguins")))
One simplification is to just leave out the let statement:
(defn make-zoo
[zoo has-ice]
(if has-ice
(conj zoo "penguins")
zoo))
(make-zoo ["tigers"] false) => ["tigers"]
(make-zoo ["polar bears"] true) => ["polar bears" "penguins"]

clojure core.typed error with assoc

So i have this bit of code
(defalias Tag
(U Keyword Integer))
(defalias Entity
(HMap :mandatory {:type Tag} :complete? false))
(defn with-prop [entity :- Entity, prop :- Keyword, value :- Any] :- Entity
(assoc entity prop value))
But it looks like with-prop is not properly typed, because core.typed says it should be:
(IPersistentMap Keyword Any)
While that is technically correct. i would like to preserve the Entity type because that guaranties the :type property is there.
is there anyway i can do that?
the only thing that interests me in this is case to have the :type property on there, it does not actually need to be a HMap, i guess it could be a IPersistentMap but i can't find a working way of adding a mandatory key to it.
(The examples on github wiki don't work for me)
I'm using version [org.clojure/core.typed "0.3.26"]
Thanks,
Boogie

Creating a Clojure macro that uses a string to call a java function

So I'm trying to make a Clojure macro that makes it easy to interop with Java classes utilizing the Builder pattern.
Here's what I've tried so far.
(defmacro test-macro
[]
(list
(symbol ".queryParam")
(-> (ClientBuilder/newClient)
(.target "https://www.test.com"))
"key1"
(object-array ["val1"])))
Which expands to the below
(.
#object[org.glassfish.jersey.client.JerseyWebTarget 0x107a5073 "org.glassfish.jersey.client.JerseyWebTarget#107a5073"]
queryParam
"key1"
#object["[Ljava.lang.Object;" 0x16751ba2 "[Ljava.lang.Object;#16751ba2"])
The desired result is:
(.queryParam
#object[org.glassfish.jersey.client.JerseyWebTarget 0x107a5073 "org.glassfish.jersey.client.JerseyWebTarget#107a5073"]
"key1"
#object["[Ljava.lang.Object;" 0x16751ba2 "[Ljava.lang.Object;#16751ba2"])
I guess the . is causing something to get evaluated and moved around? In which case the solution would to be to quote it. But how can I quote the results of an evaluated expression?
My goal is to convert maps into code that build the object by have the maps keys be the functions to be called and the values be the arguments passed into the Java functions.
I understand how to use the threading and do-to macros but am trying to make request building function data driven. I want to be able take in a map with the key as "queryParam" and the values as the arguments. By having this I can leverage the entirety on the java classes functions only having to write one function myself and there is enough of a 1 to 1 mapping I don't believe others will find it magical.
(def test-map {"target" ["https://www.test.com"]
"path" ["qa" "rest/service"]
"queryParam" [["key1" (object-array ["val1"])]
["key2" (object-array ["val21" "val22" "val23"])]] })
(-> (ClientBuilder/newClient)
(.target "https://www.test.com")
(.path "qa")
(.path "rest/service")
(.queryParam "key1" (object-array ["val1"]))
(.queryParam "key2" (object-array ["val21" "val22" "val23"])))
From your question it's not clear if you have to use map as your builder data structure. I would recommend using the threading macro for working directly with Java classes implementing the builder pattern:
(-> (ClientBuilder.)
(.forEndpoint "http://example.com")
(.withQueryParam "key1" "value1")
(.build))
For classes that don't implement builder pattern and their methods return void (e.g. setter methods) you can use doto macro:
(doto (Client.)
(.setEndpoint "http://example.com")
(.setQueryParam "key1" "value1"))
Implementing a macro using a map for encoding Java method calls is possible but awkward. You would have to keep each method arguments inside a sequence (in map values) to be a able to call methods with multiple parameters or have some convention for storing arguments for single parameter methods, handling varargs, using map to specify method calls doesn't guarantee the order they will be invoked etc. It will add much complexity and magic to your code.
This is how you could implement it:
(defmacro builder [b m]
(let [method-calls
(map (fn [[k v]] `(. (~(symbol k) ~#v))) m)]
`(-> ~b
~#method-calls)))
(macroexpand-1
'(builder (StringBuilder.) {"append" ["a"]}))
;; => (clojure.core/-> (StringBuilder.) (. (append "a")))
(str
(builder (StringBuilder.) {"append" ["a"] }))
;; => "a"

How should I build a list and return it in clojure?

I'm still learning this alien functional paradigm...
How would I write the following code in Clojure, and in a functional way?
assume this missing parts are defined elsewhere and behave as described in the comments.
Here it is in Python, which I am familiar with.
usernames = []
# just the usernames of all the connections I want to open.
cancelfunctions = {}
# this global contains anonymous functions to cancel connections, keyed by username
def cancelAll():
for cancel in cancelfunctions.values():
cancel()
def reopenAll():
cancelfunctions = {}
for name in usernames:
# should return a function to close the connection and put it in the dict.
cancelfunctions[name] = openConnection()
All I really need to know is how to build up a new dict of callbacks, like in the reopenAll function, but I'm including some more context here because chances are I'm committing some kind of functional paradigm atrocity, and you will most likely want to fix the whole program. :)
Building data structures in Clojure often involves reduce, which feeds a sequence of inputs to a function which accumulates a final return value. Here are two ways to write a function which constructs a map (i.e. dictionary) of username to the return value of open-connection.
;; Using reduce directly
(defn reopen-all [usernames]
(reduce
(fn [m name] (assoc m name (open-connection)))
{} usernames))
;; Using into, which uses reduce under the hood
(defn reopen-all [usernames]
(into {} (for [name usernames]
[name (open-connection)])))
Note that these two functions return a value and do not mutate global state, as your Python code does. Global state isn't inherently bad, but it's good to separate value-generation from state manipulation. For state, you'll probably want an atom:
(def usernames [...])
(def cancel-fns (atom nil))
(defn init []
(reset! cancel-fns (reopen-all usernames)))
And here's cancel-all for completeness' sake:
(defn cancel-all []
(doseq [cancel-fn (vals #canel-fns)]
(cancel-fn)))
Here's a functional approach in python:
def reopen(usernames):
return dict((name, openConnection()) for name in usernames)
You may find it easier to "translate" to a functional style in python before attempting to use a primarily functional language.

In Clojure how to choose a value if nil

In Clojure what is the idiomatic way to test for nil and if something is nil then to substitute a value?
For example I do this a lot:
let [ val (if input-argument input-argument "use default argument")]
: but I find it repetitive having to use "input-argument" twice.
just use or:
(or input-argument "default")
Alex's suggestion of "or" is indeed the idiomatic way to rewrite your example code, but note that it will not only replace nil values, but also those which are false.
If you want to keep the value false but discard nil, you need:
(let [val (if (nil? input-argument) "use default argument" input-argument)]
...)
If you only bind the variable to do get the right value and not to use it twice there is a other way you can do it. There is a function in core called fnil.
You call fnil with the function you want to call and the default argument. This will return a function that will replace nils with the default value you provided.
The you can do one of the things depending on what you want. Creat a local function.
(let [default-fn (fnil fn-you-want-to call "default-argument")]
(default-fn input-argument))
In somecases (where you always have the same default argument) you can move to logic to do this out of your code and put it where to original function was (or wrap the function in case it in a other library).
(defn fn-you-want-to-call [arg] ....)
(def fn-you-want-to-call-default (fnil fn-you-want-to-call "default-argument"))
Then in your code its reduced to just
(fn-you-want-to-call-default input-argument)
More you can find here:
http://clojuredocs.org/clojure_core/clojure.core/fnil
When the expected value is a boolean I recommend using an util fn.
(defn- if-nil [default val]
(if (nil? val)
default
val))
(if-nil true (possible-false input))