Modyfing higher order functions output in ClojureScript - clojure

I want to create helper function that modifies output returned by higher-order function.
Example of higher-order function:
(def use-meta-sub (make-app-fn (make-sub :meta)))
The problem is that when using this in let like this:
(let [meta-sub (use-meta-sub props :get-me-meta-of-this)])
returns map of key-value pairs like this:
{:key-we-almost-never-need-1 nil
:key-we-almost-never-need-2 nil
:key-we-almost-never-need-3 nil
:key-we-almost-never-need-4 nil
:meta-data {:something-useful "foo"
:more-usefull "bar"
:and-so-on "baz"}}
I would like to target only this :meta-data key
I tried this and some other variations:
(defn use-meta-data-sub [props ctrl]
(:meta-data (use-meta-sub props ctrl))) ;; both with get
It does not work because (I think, that returns lazy sequence and I do not know how to actually firs evaluate it and then extract the key from output).
Is this possible without editing 1st higher-order function, and other two it contains?
(I read all documentation on clojure site and clojure-unraveled, either I do not understand them, or they do not cover this)

Related

In EDN, how can I pass multiple values to tagged element returned from other tagged elements

I have following EDN
{
:test #xyz/getXyz #abc/getAbc #fgh/getFgh "sampleString"
}
In Clojure, I have defined implementation for each of the tagged element which internally calls java functions. I have a requirement in which I need to pass return values of both #abc/getAbc and #fgh/getFgh to #xyz/getXyz as separate parameters.
In my current implementation #fgh/getFgh gets called with "sampleString". And with the output of #fgh/getFgh, #abc/getAbc gets called. And with its output #xyz/getXyz gets called.
My requirement is #xyz/getXyz should get called with return value of both #abc/getAbc and #fgh/getFgh as individual parameters.
Clojure implementation
(defn getXyz [sampleString]
(.getXyz xyzBuilder sampleString)
)
(defn getAbc [sampleString]
(.getAbc abcBuilder sampleString)
)
(defn getFgh [sampleString]
(.getFgh fghBuilder sampleString)
)
(defn custom-readers []
{
'xyz/getXyz getXyz
'xyz/getAbc getAbc
'xyz/getFgh getFgh
}
)
I want to modify getXyz to
(defn getXyz [abcReturnValue fghReturnValue]
(.getXyz xyzBuilder abcReturnValue fghReturnValue)
)
You can't do exactly what you are asking. The tag can only process the following form. That said, you can alter the syntax for your Xyz EDN so that it can support taking a vector of [Abc Fgh] pair.
{:test #xyz/getXyz [#abc/getAbc "sampleString" #fgh/getFgh "sampleString"]}
I'm not sure if you meant that getAbc still needed to take getFgh as input or not. If so, it would be more like:
{:test #xyz/getXyz [#abc/getAbc #fgh/getFgh "sampleString" #fgh/getFgh "sampleString"]}
Now your getXyz tagged reader will receive a vector of Abc and Fgh. So you'll need to change your code to grab the elements from inside the vector, something like that:
(defn getXyz [[abcReturnValue fghReturnValue]]
(.getXyz xyzBuilder abcReturnValue fghReturnValue))
This uses destructuring syntax (notice that the arguments are wrapped in an extra pair of bracket), but you could use first and second if you wanted instead, or any other way.

How can I execute custom tag readers in different order in Clojure EDN

I have a following EDN file
:abc #request/builder/abc {
"def" #request/builder/def {
"someVector" ["sample1", "sample2"]
}
}
I have defined custom tag reader in Clojure, which internally calls java code
(defn custom-readers []
{
#request/builder/def defBuilder
#request/builder/abc abcBuilder
}
)
(defn defBuilder [params]
(.defBuilder (someJavaUtilityClass.) params)
)
(defn abcBuilder [params]
(.abcBuilder (someJavaUtilityClass.) params)
)
When I read EDN using edn/read-string, defBuilder executes first and its value gets passed to abcBuilder.
I want to reverse the order of execution without modifying EDN. I want to modify abcBuilder code such that if java call in abcBuilder returns some value then only execute defBuilder. How can I achieve this.
I tried by modifying code as below
(defn defBuilder [params]
'(.defBuilder (someJavaUtilityClass.) params)
)
(defn abcBuilder [params]
if((.abcBuilder (someJavaUtilityClass.) params)
(eval (get params "def"))
)
)
But this throws error like it "Unable to resolve someJavaUtilityClass and params". Is there a better way to solve this?
I'm afraid that's not possible. That isn't how EDN's tagged literals work. The tag handler is called after reading the form, which includes calling the tag handlers for any tagged literals in the form. In other words, the tag handlers are called inside-out.
If this weren't the case, then what a tag means will depend on where that tagged literal is situated, which is needlessly context dependent.
Check out: https://github.com/edn-format/edn#tagged-elements
Here's the relevant part:
Upon encountering a tag, the reader will first read the next element (which may itself be or comprise other tagged elements), then pass the result to the corresponding handler for further interpretation, and the result of the handler will be the data value yielded by the tag + tagged element, i.e. reading a tag and tagged element yields one value.
Also check out: https://clojure.org/reference/reader#tagged_literals
This is about the Clojure reader. And again, here is the relevant bit:
by invoking the Var #'my.project.foo/bar on the vector [1 2 3]. The data reader function is invoked on the form AFTER it has been read as a normal Clojure data structure by the reader.
Also, symbols can only contain one /, delimiting the namespace and the name. Check out: https://github.com/edn-format/edn#symbols

NullPointerException clojure.core/filter/fn

Why does:
(filter f xs)
, result in an error that starts like this:
NullPointerException clojure.core/filter/fn
filter does not accept nil as its first (function) argument.
IMO because when you look into filter implementation there is no check if f is a function or not. I expect that is done like this for a performance reason. E.g. string module doesn't check a given string for nil too, because of a performance (https://github.com/clojure/clojure/blob/master/src/clj/clojure/string.clj#L19).

Create a keyword from a number

tl;dr
How can I derive a keyword from a number in ClojureScript:
(keyword 22)
;;=> :22 but in fact returns nil.
Background
In my ClojureScript/Hoplon application I make HTTP requests via cljs-http. Parts of the response I receive look like this:
{:companies
{:22 {:description ... } ; A company.
:64 {:description ... }
... }
{:offers
[{:description ... } ; An offer.
{:description ... }
... ]
Each offer within the vector behind :offers has a :companyId which represents a key in :companies. As soon as I receive the response, I reset! a cell (similar to an atom) query.
Now, I'd like to iterate over each offer and call a function offer-tpl that creates the corresponding HTML. In order to do so, offer-tpl needs the offer itself as well as the related company:
(for [offer (:offers #query)]
(offer-tpl offer (get-in #query [:companies (keyword (:companyId offer))]))))))
Despite the fact that this surely can be done more elegant (suggestions very appreciated), the get-in doesn't work. (:companyId offer) returns a number (e.g. 22) but (keyword (:companyId offer)) returns nil. Calling (keyword (str (:companyId offer))) does the trick, but aren't there any other ways to do this?
(keyword "22") or (keyword (str 22)) returns :22
The reason you are getting :22 is likely because of the keywordize-keys option of a JSON translation. For example:
cljs-http defaults to keywordize-keys for jsonp:
https://github.com/r0man/cljs-http/blob/1fb899d3f9c5728521786432b5f6c36d1d7a1452/src/cljs_http/core.cljs#L115
But you can (and should) in this case pass in a flag to disable keywordization.
Not all keys in JSON are appropriate for Clojure keywordization. For example spaces in a JSON key are valid, but not in Clojure.
Please be aware that numeric keywords are probably incorrect.
https://clojuredocs.org/clojure.core/keyword#example-542692cec026201cdc326d70
It seems like that caveat has been removed from the current Clojure website, so perhaps that means something but I'm not sure what.
http://clojure.org/reference/reader Currently states that
Keywords - Keywords are like symbols, except: They can and must begin
with a colon, e.g. :fred. They cannot contain '.' or name classes.
Like symbols, they can contain a namespace, :person/name A keyword
that begins with two colons is resolved in the current namespace: In
the user namespace, ::rect is read as :user/rect
and that
Symbols begin with a non-numeric character and can contain
alphanumeric.
This definition of a keyword excludes :22 and :with spaces
The keyword function returns a result for invalid input, but this is not an endorsement, it is simply because checking for incorrect input would be a performance overhead in a core part of Clojure.
In short, not all JSON keys translate to keywords, so you should avoid keywordize-keys unless you know the keyspace and/or doing so provides some conveniences.

Using list values to form single redis mget

I have a clojure list
("mykey:1" "mykey:2" "mykey:3")
I want to use redis mget to fetch values of all keys
(mget mykey:1 mykey:2 mykey:3)
I'm using the wonderful Carmine library.. I don't have any problem with it at all but when I try to use the list in a function
(defn get-keys
[k]
(mget k))
The key k actually includes the brackets too, since it's a list. Doing:
(mget (map #(%) k))
gets me nowhere either.
How do I now split them into individual keys so I can pass it to mget? is that possible?
Thanks
When you have a collection that contains values you want to use as the arguments to a function, you should use apply.
(def args '("mykey:1" "mykey:2" "mykey:3"))
(apply mget args)
; is equivalent to the call
(mget "mykey:1" "mykey:2" "mykey:3")