This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-10-19
Channels
- # adventofcode (1)
- # announcements (3)
- # babashka (60)
- # beginners (60)
- # calva (5)
- # clj-commons (17)
- # clj-kondo (33)
- # clj-on-windows (1)
- # clojure (40)
- # clojure-austin (3)
- # clojure-europe (19)
- # clojure-gamedev (25)
- # clojure-nl (1)
- # clojure-norway (6)
- # clojure-sweden (4)
- # clojure-uk (2)
- # clojurescript (27)
- # conjure (1)
- # core-async (1)
- # core-typed (7)
- # cursive (5)
- # datomic (35)
- # events (1)
- # fulcro (35)
- # integrant (7)
- # introduce-yourself (2)
- # kaocha (5)
- # leiningen (2)
- # lsp (26)
- # malli (13)
- # nbb (99)
- # off-topic (15)
- # pathom (12)
- # pedestal (5)
- # polylith (8)
- # portal (4)
- # rdf (19)
- # reagent (8)
- # reitit (5)
- # releases (2)
- # remote-jobs (2)
- # rewrite-clj (1)
- # shadow-cljs (94)
- # testing (2)
- # timbre (2)
- # tools-deps (16)
Hi, How to use npm modules correctly in clojurescript for the below code
import axios from 'axios';
import { aws4Interceptor } from "aws4-axios";
const client = axios.create({ baseURL: BASE_UEL, headers: {appkey: 'test'}});
client.interceptors.request.use(aws4Interceptor({
region: AWS_REGION,
service: "execute-api",
},
{
accessKeyId: AWS_ACCESS_KEY_ID,
secretAccessKey: AWS_SECRET_ACCESS_KEY,
}
));
(PATH, JSON.stringify(body))
This is a snippet from when I used shadowcljs to write an 'npm' module in clojurescript - I am calling a core nodejs (net) and an npm dep (protobufjs):
(ns fnrc.core
(:require ["net" :as net]
["protobufjs" :as proto]))
(def schema (atom nil))
(defn load-schema []
(->
(proto/load (str js/__dirname "/src/main/fnrc/proto.proto"))
(.then #(reset! schema %))
(.catch #(reset! schema (.toString %)))))
(defn load-schema-cb []
(proto/load (str js/__dirname "/src/main/fnrc/proto.proto")
(fn [err root]
(if err
(reset! schema (.toString err))
(reset! schema root)))))
main thing is in your require area you have to quote the npm/nodejs import (the "from <whatever>" segment in your sample) - the rest would be basic clojure(script) interop for how to chain the functions as are done in your sample - and some of my snippet is not relevant to your Q, it was just the smallest sample I could find (shows promise chaining as well)
Hi All, I have a map with optional keys - {:target_loss 980 :target_date "19-Mar-2020"} I have below spec to validated if these keys are available then target_loss is positive and target_date is a valid date. Spec doesn't seem to be working correctly, it never validates the second key target_date. What is the way to combine specs, Is there a way I can see the complete spec that is being constructed?
(def not-nil? #(not (nil? %)))
(def is-valid-date? #(and (string? %) (inst? (Date.))))
(def is-pos? #(and (nat-int? %) not-nil?))
(spec/def :int/non-negative is-pos?)
(spec/def :string/is-valid-date is-valid-date?)
(spec/def :client-supplied-request/target_loss :int/non-negative)
(spec/def :client-supplied-request/target_date :string/is-valid-date)
(spec/def :client-supplied-request/target_loss_key
(spec/keys :opt-un [:client-supplied-request/target_loss]))
(spec/def :client-supplied-request/target_date_key
(spec/keys :opt-un [:client-supplied-request/target_date]))
(spec/def :client-supplied-request/client-supplied-targets
(spec/and :client-supplied-request/target_loss_key :client-supplied-request/target_date_key))
(defn is-valid-map? [spec map-input]
(println spec/describe)
(println map-input)
(let [parsed (spec/conform spec map-input)]
(if (spec/invalid? parsed)
(throw (ex-info (format "Invalid input: %s"
(json/write-str (spec/explain-data spec map-input))) {:cause :bad-request}))
(spec-tool/conform spec map-input spec-tool/strip-extra-keys-transformer))))
json-request (api-input-spec/is-valid-map? :client-supplied-request/client-supplied-targets {:target_loss 980 :target_date "19-Mar-2020"})]
even if I replace that with simple spec i.e.
:client-supplied-request/target_date :int/non-negative
it doesn't workI passes the validation even though i pass wrong input
there are several issues in the spec I pointed out, have you fixed those? are you using a different spec now? what is the different spec?
If I replace (spec/def :client-supplied-request/target_date :string/is-valid-date) with (spec/def :client-supplied-request/target_date :int/non-negative) then also it passes the validation with wrong input
(spec/def :int/non-negative is-pos?)
{:target_lpi_as_date_str "fff" :target_enrollment 333}
:target_lpi_as_date_str "fff"
this should fail since this is not an integer:target_date "fff"
this is the key
Yes, I just tweaked the actual code to make it simpler
{:target_date "fff" :target_loss 333}
(spec/def :client-supplied-request/target_loss :int/non-negative)
(spec/def :client-supplied-request/target_date :int/non-negative)
(def is-pos? #(and (nat-int? %) not-nil?))
(spec/def :int/non-negative is-pos?)
(spec/def :client-supplied-request/client-supplied-targets
(spec/keys :opt-un [:client-supplied-request/target_loss :client-supplied-request/target_date]))
I am trying to get all the pieces together in one place, because getting the parts here and there separate has resulted in lots of disjointed bits that don't match each other
Not sure if it explains the problem but the definition of is-pos?
is wrong, it should be:
(def is-pos? #(and (nat-int? %) (not-nil? %))
Yes but if the input is a nat-int then not-nil?
is evaluated and is-pos?
returns that
(require '[clojure.spec.alpha :as spec])
(import '(java.util Date))
(def not-nil? #(not (nil? %)))
(def is-valid-date? #(and (string? %) (inst? (Date.))))
(def is-pos? #(and (nat-int? %) not-nil?))
(def is-pos? #(and (nat-int? %) not-nil?))
(spec/def :int/non-negative is-pos?)
(spec/def :client-supplied-request/target_loss :int/non-negative)
(spec/def :client-supplied-request/target_date :int/non-negative)
(spec/def :client-supplied-request/client-supplied-targets
(spec/keys :opt-un [:client-supplied-request/target_loss :client-supplied-request/target_date]))
(spec/valid? :client-supplied-request/client-supplied-targets {:target_date "fff" :target_loss 333})
is the facts as I understand it, put together in a nice neat package that anyone can paste right into a repl and try out
trying.....
so, either the spec you are sharing is not what you are actually running, or you are misinterpreting results of a larger program, or ...
there was a typo in the key, it worked.
thanks a lot @U0NCTKEV8
Share it in clojurescript but I think it will be suitable for this channel too.
I am trying to use react-flow in my shadow-cljs project, but can't figure out to write onNodeChanges handler. Instead of using useState I used reagent-atom and instead of callback function. I simply used atom reset but it is giving me the error Uncaught TypeError: t$jscomp$0.reduce is not a function
. Here is the link for official documentation. https://reactflow.dev/docs/getting-started/adding-interactivity/
const [nodes, setNodes] = useState(initialNodes);
is replaced with
(def nodes (r/atom initial-nodes))
const onNodesChange = useCallback((changes) => setNodes(applyNodeChanges(changes, nodes)), []);
is replaced with
(defn on-node-change [changes]
(let [new-nodes (apply-node-changes changes @nodes) ] (reset! nodes new-nodes ))
What I am doing wrong ?Welcome π.
If you want to cross-post (usually shouldn't be necessary but :man-shrugging:), your best option is to post once, and then link to that in other channels. That directs everyone to the same place to respond.
And for long posts like this, it is nice if you first post just your question, and start a thread for extra details and code.
You can create code blocks by typing `. That makes your code way easier to read.
Nothing about your code example jumps out as being wrong. You probably want to narrow down where the error is happening.
What's the benefit of destructuring in functions parameters vs doing it in the body? will the destructuring happen before passing the value the to the function?
If you clojure.walk/macroexpand-all
, you can see that that destructuring happens in the body of the function:
> (clojure.walk/macroexpand-all '(defn foo [{:keys [a b c]}]))
(def
foo
(fn*
([p__33970]
(let*
[map__33971
p__33970
map__33971
(if
(clojure.core/seq? map__33971)
(if
(clojure.core/next map__33971)
(.
clojure.lang.PersistentArrayMap
createAsIfByAssoc
(clojure.core/to-array map__33971))
(if
(clojure.core/seq map__33971)
(clojure.core/first map__33971)
clojure.lang.PersistentArrayMap/EMPTY))
map__33971)
a
(clojure.core/get map__33971 :a)
b
(clojure.core/get map__33971 :b)
c
(clojure.core/get map__33971 :c)]))))
destructuring in the function parameters can be useful to communicate a bit about the shape of the data the function accepts. As a made up example:
(defn my-parse [form {:keys [opts keywordize? on-error]}])
You can see that the second argument to my-parse
can have the keys opts
, keywordize?
, and on-error
.Other than that, I don't think it matters that much. You can also go overboard in trying to communicate too much through destructuring (relying on the :or
of a destructure is a common example).
The function signature (or arglists, there can be multiple for a single function) is used by number of tools. For my personal setup (emacs+nrepl+cider), it shows up as I'm typing.
And as you mentioned, it also gets picked up by several documentation generators.
user> (defn parse [form {:keys [opts keywordize? on-error]}])
#'user/parse
user> (meta #'parse)
{:arglists ([form {:keys [opts keywordize? on-error]}]),
:line 74,
:column 7,
:file "*cider-repl workspace/desk:localhost:60870(clj)*",
:name parse,
:ns #namespace[user]}
this is a context sensitive thing. in my current app all my web resource handlers use destructuring in the function def, but not many other functions in my code do. it's just a convention that i found useful.
In Calva, I see a full function signature, including destructuring, along with doc strings, when I hover the mouse over the name of a function. This tells me which keys my map needs to have, or gives meaningful names to parts of a tuple.
Also sometimes you have a larger map that your function only needs one or two keys from, in this case destructuring (at least as long as it is without :as
) also lets the caller know that you will not be messing with the other keys in the map (say a ring request with a ton of stuff and you only care about two headers).
"in what scenarios do you see the function signature and not the body"
I think any time I look at a function to find out what it does and how to use it, I want to be able to avoid a deep dive into the body, even though it is right there. I just want a quick synopsis that, again, might spare me digging into the body. Having the destructuring in the function parameter list makes the synopsis a bit richer.
But, tbh, many times a function is really expecting a specific control block as a parameter. If there is no :as
to communicate that, the code feels a bit obfuscated/clever.