Fork me on GitHub

it should look something like

(fn [f] (fn [req] (update-in (f req) [:cookies] conj "whatever")))

Mario C.00:05:22

(defn- wrap-jwt-payload
  (let [jwt     (jwt/get-token request)
        payload (jwt/decode-token jwt)]
    (prn jwt)
    (-> (update-in request [:params] merge payload)
        (update-in [:cookies] merge (->> (jwt/create-token payload (jwt/token-lifetime))

Mario C.00:05:07

The prn would print out the old jwt. But a new jwt cookie was never set, as in the old one was never overwritten by the new one


I am shocked that it printed anything


because that is just wrong, the middleware wrapping functions are all functions that return a function


they are functions from handlers to handlers, not functions from requests to responses

Mario C.00:05:18

oh yea I see how thats confusing.. Its not an actual middleware function

Mario C.00:05:37

Its returning a modified request which gets passed to a handler function


It's confusing to call it wrap-... then...

Mario C.00:05:12

Yea thats true, ill probably change the name


Cookies needs to be set in the response, and that function does it's update in on the passed in request


So that is also potentially confusing


It would be better as middleware since it could decode the JWT on the way in, add the payload to the request, call the handler, then add an updated JWT to the response before returning that (updated response).

Mario C.00:05:53

So thats the reason why I added it in the middleware but I need to figure out why its not working


@mario.cordova.862 Middleware should have this general pattern:

(defn wrap-something
  (fn [req]
    (let [resp (handler (enhance req))]
      (enhance resp))))


In your case, you'd want to decode the JWT in that let and enhance would include that update-in that merged in the payload to the request :params.


And then the enhance on the response would merge the updated JWT into the :cookies.


Does that make sense?


(And note that those are two different enhance functions)

2️⃣ 4
Mario C.01:05:17

@seancorfield yes it makes sense. @smith.adriane gave an example earlier which pretty much mirrors yours. And that’s what I did to get it working. Thank you guys, I appreciate the help :)


:jvm-opts not supported at the top level of deps.edn?


no, only :deps , :paths , :aliases and provider-specific keys (as :mvn/repos) supported as a top-level keys in deps.edn


Thank you for confirming.

Endre Bakken Stovner12:05:45

I am writing a workflow management system, something like GNU make. I have jobs in one of four states: done, running, ready, or not ready (i.e., dependencies missing). Each category has one set each, containing job ids. I guess each set should be in the same atomic map, to ensure atomic updates.

{:done #{1 2}
 :running #{3 6}
 :ready #{4 5 7}
:not-ready #{8 9 10}
When jobs finish, I need to move them from running to done. I also need to recompute the ready set, to see if any not ready jobs are now ready. Multiple jobs might be running and finishing simultaneously. What would be a Clojure-y way of doing this? I guess when jobs finish, they can call a function that 1) moves them from running into done 2) recomputes the ready set Is any chain in my thinking bad? There might be a better way to do this than an atom of sets which the finished jobs try to update themselves. It is the final part which feels like it is complecting stuff; the jobs adding themselves to the done set. Also, when the ready set is updated, new jobs should be dispatched.

Ben Sless13:05:28

Why do jobs need state? Introspection / monitoring? You have a graph of dependencies. You can "compile" the graph and make sure there are no circular or missing deps, then separately build an execution model for a graph. Once you linearize the graph via topological sort you just need a task model and pass it to any executor. Is there even a need to track the state of every node in the graph?

Scott Starkey13:05:44

Hi @UT770EY2K. I’m watching this thread, because I’m a beginner and doing exactly this! I have a dice game I’m working on, and the dice can be in various states: behind a shield, in play, or at rest. The way I handled it was to have a key map, almost exactly like you have above. Then when I move the used dice with assoc-in and update-in to :at-rest after they are used, and back to :behind-shield once they are rested. I’m not sure if this is Clojure-y or not, but it makes sense to me! 👼

Endre Bakken Stovner06:05:35

@UK0810AQ2 Yes: monitoring (dashboard), reprioritization of jobs whilst running, and probably more neat stuff I have not thought of yet.

Endre Bakken Stovner06:05:26

@UH0FTE610 Cool, but it seems like a case of newbs leading the newb XD. There might be a better way we do not know about.

Endre Bakken Stovner06:05:53

Was my question unclear/too long? Are there design patterns for this somewhere? Or was my naive suggestion actually ok and that was the reason for few replies XD

Endre Bakken Stovner06:05:56

Asked a new, simplified and more general q right now :)

Cas Shun14:05:12

Is there a function that gives me the position of regex matches? I need to split a string on regex matches and know which strings matched or not (I could use clojure.string/split, then re-run the regex on each item, but that seems inefficient?)


you can use re-matcher with a bit of interop

Cas Shun14:05:35

cool idea, I'll try that thank you


(let [m (re-matcher #"\d+" "qwe12345rty678ui")]
  (loop [acc [] match? (.find m)]
    (if match?
      (let [mr (.toMatchResult m)]
        (recur (conj acc {:pos [(.start mr)
                                (dec (.end mr))]
                          :res (.group mr)})
               (.find m)))
something like this should work

Michael Stokley14:05:00

the documentation of clojure.spec.alpha/fdef says that :args and :ret are require for :fn. is that still true?

Note that :fn specs require the presence of :args and :ret specs to
conform values, and so :fn specs will be ignored if :args or :ret
are missing.


say I’m creating a dynamic macro and also want to pass it a dynamic macro symbol

`(defmacro foo []
   `(~~sym ~@args))
when the macro’s symbol was coming from another package, ~~sym that worked fine. but within the same namespace (I was providing default value) I had to use ~'~sym to get it working
`(defmacro foo []
   `(~'~sym ~@args))
I imagine adding the quote tells it not to evaluate the macro, but why is the extra quote only necessary within same namespace? Is it some special case in how macro expansion is handled?


Also, does anyone have a better mental model for complex quoting and unquoting like ~'~ , I at first had tried '~~ thinking I wanted to first fully retrieve the symbol and then quote it, not too sure of how to think of former one.


the backtick ` operator will replace symbols with their fully qualified versions:

user> `foo


if the symbol can’t be resolved, then it will just use the current namespace


the symbol I was passing was already backticked and resolved


ymmv, but in general, I probably would avoid writing macros that write macros directly


depending on the use case, there’s probably an easier way


also, ~foo gets expanded to (clojure.core/unquote foo) :

> (pr-str (read-string "~+"))
"(clojure.core/unquote +)"
I imagine that might be where your original error was originating


hmm i don’t think there is, the use-case is making it easier to wrap entire react libraries i.e.

(intern-comps `react-native '[View Text Input])
it needs to be a dynamic macro so that cljs arguments are pre-compiled to js ones


doubling up syntax quote like that is likely not required, and can be confusing


if you already inside a syntax quote, you can usually use a plain quote instead of adding another layer of syntax quoting


ah interesting, so this?

`(defmacro foo []
   '('~sym ~@args))


user=> (eval ``(~@[1 2]))
(1 2)
user=> (eval `'(~@[1 2]))
(1 2)


thanks, that’s a great tip, the extra backticks get confusing


dunno, I haven't read that much of what you are doing, but with no context my guess would that isn't correct


I know doing macrology with cljs can sometimes require some dark magic, but I’m still not sure why a macro that makes a macro would be necessary. i’m generally curious since it’s not totally implausible and sounds interesting.


usually macros that write macros can be turned into macros that expand into calls to other macros


i can post a link in a bit

😁 4

obviously, I understand it may be a complete waste of time for you to explain it to me


macros are not composable, so long term it is better to crack open a macro then to build on one. I don't write any cljs, but my general impression is it has a real problem with an abundance of macros


my reasoning for macros writing macros being unnecessary is that I can’t think of a reason why code produced via “macros -> macros -> code” couldnt’ be produced with simply “macros -> code”


cljs can complicate issues compared to clj since macros are only available at compile and manipulation of namepaces/vars programmatically is limited. if you’re trying to target bootstrapped cljs, then things get even more complicated


@smith.adriane yea it’s for cljs so I’m sure that complicates it. here’s the repo (still very much WIP): if there’s a better way of getting to “macros -> code” I’d love to know

👀 4

you are mixing compile time and runtime state pretty liberally


at compile time/macro expand time the `rr you pass into interop/intern-comps is just a symbol


yes, i do fear that since i’m still new with macros I might be doing that. but I’m not sure i understand the specific issue you mentioned


and you are adding extra quoting to it


in the code itself i resolve the symbol


do you have an example of how you use the interned variables?


you can't pass non-literal arguments to macros


I quote the symbol b/c linter gives “unresolved symbol errors”


so i manually remove quote inside macro, and resolve symbol


maybe bin the linter instead


i use vscode with clj-kondo 😅


so for a macro (and this is extra true for cljs) if have (def x 1) and (some-macro x) the macro never gets 1


when you say (def x <any-expression>) you are defining x to be the result of evaluating the expression


and the result of evaluating the expression doesn't exist until runtime


@smith.adriane yes but example isn’t public rn, I can add one to repo later. but basically you’d use them like regular react components


which in the case of clojurescript, compile time is on the jvm and runtime is on a js vm, so they don't really share anything (they are kind of mixed in clojure)


so the name is interned via createElement ?


yeah, sorry, so in this case I don’t resolve the symbol I just add code for retrieving its component object


but it doesn't exist at macro expand time


so `rr is wrapped in this

(defn js-module* "Macro helper for getting js module, throws error if module does not exist."
       [sym k]
       `(if (goog.object/get ~sym ~k)
          (goog.object/get ~sym ~k)
          (throw (ex-info "Interned component not found" {:sym ~sym :key ~k}))))


thanks @borkdude will take a look. though tbh I didn’t mind manually adding the ' to the symbol


but that was the wrong thing to do


you should not being adding quoting to symbols passed to macros


@alidcastano hiredman is right. if you quote the symbol, the macro will see (quote a) instead of a.


which is why I rather flippantly suggested binning the linter


My clojurescript atom has a vector of words ["one" "word" "two" "blurred"] and i'm wondering why str/join is not making them into one string like I want.

Alex Porter17:05:10

You have to deref your atom like this:

(def my-atom (atom ["one" "word" "two" "blurred"]))
(clojure.string/join " " @my-atom)


i.e. a list instead of a symbol


because you aren't derefing the atom


@borkdude @hiredman I see, yeah I was incorrectly working around that, i.e. (if (and (seq? x) (= (first x) 'quote)) (second x) x)) , rather than knowing I had to configure the linter. thanks for clarifying that


I have started using clj-kondo a little at work, and I haven't found it to be a radical departure from other linters in that it is 80% keeping stuff tidy and 20% complaining about things that are correct the way they are


and that 20% is rather maddening and causes people to do things like add quoting or just declare the names of locally bound symbols in anaphoric macros


that's why the config exists. all the clojure code bases I've been working on have a fairly minimal config to get that 20% down to 0%

👍 4

thanks hiredman, I am derefing it with @ though. output: ["はくじょ" "が" "きく"] what i doin: (.log js/console (str/join @stale-stack-jp))


I just strongly suggest you never abandon your own judgment for the linters


yeah, agree. don't follow tools blindly


sova your atom contains an a vector of a vector of strings, not a vector of strings


Ah. Thanks. How can I ensure I'm not appending new vectors?


just don't do it


@alidcastano, going back to your question. I think you want something like:

(defmacro intern-comps [sym tags]
     ~@(for [tag tags]
         `(defn ~tag [args#]
            (~'.apply  react/createElement  nil (~'clj->js (into [(~'js-module* ~sym ~tag)] args#)))))))
which will produce something like:
> (macroexpand-1 '(intern-comps  rn [View]))
     [(js-module* rn View)]


but the generated components won’t pre-compile their props/args, right? i was creating a macro for each one because their factory/compiler function is a macro


so for example, it could be used with Helix library $ macro, which pre-compiles components props


your code only had createElement as compiler, which isn’t a macro


yea just figured it’d be good to provide a default


but the intern-comps macro should still produce a function


I’m not familiar with helix


the example shows usage

(interop/intern-comps `rr
                       [View Text]
                       {:compiler 'helix.core/$})


i don’t think it can produce a function because it’s wrapping a compiler macro


to be clear compile-element was the compiler


and createElement was its generated code


it looks trivial in code because it’s just a default value


ok, sounds reasonable. I’m not familiar enough with the cljs compiler to know if dynamically generated macros would cause issues, but I don’t think it should.


but fwiw, I would probably do something like:

(defmacro $ [sym & args]
  `(helix.core/$ ~(js-module* ~(namespace sym) ~(name sym)) ~@args))
;; use directly
($ rn/View {:style {}} "child1" "child2")


thanks for taking the time to explain it to me. it is an interesting use case


yea this is definitely a convenience macro for nicer syntax i.e. (c/view (c/text "Hello")) versus ($ rn/View ($ rn/Text "Hello") , don’t want to see the $ symbols when rendering core components and of course, thanks for taking a time to look at code and always offering advice/suggestions

👍 4

I was using conj, moving to concat seems to have done the trick

Daniel Östling18:05:29

Hello, I've done something stupid and I can't figure it out 🙂

Daniel Östling18:05:07

I get a strange ns scoping error, like this:

Daniel Östling18:05:25

java.lang.RuntimeException: Unable to resolve symbol: parse-line in this context
clojure.lang.Compiler$CompilerException: Syntax error compiling at (mvp_test/core.clj:7:3).
    data: {#object[clojure.lang.Keyword 0x3bcc8f13 ":clojure.error/phase"] #object[clojure.lang.Keyword 0x6f112f70 ":compile-syntax-check"], #object[clojure.lang.Keyword 0x342723a3 ":clojure.error/line"] 7, #object[clojure.lang.Keyword 0xf3876ef ":clojure.error/column"] 3, #object[clojure.lang.Keyword 0x6b751cb1 ":clojure.error/source"] "mvp_test/core.clj"}
             clojure.lang.ExceptionInfo: Syntax error compiling at (mvp_test/core.clj:7:3).

Daniel Östling18:05:08

Code is:

(ns mvp-test.core
  (:require [instaparse.core :as insta]))

(defn do-parse
  (parse-line line))

(def parse-line
   "logline = #'.*'"))

(defn -main
  [& args]
  (when (empty? args)
      (println "Need line to parse")
      (System/exit 1)))
  (let [line (first args)]
    (do-parse line)))


compilation is single pass form at a time

Daniel Östling18:05:31

And build.boot is


you can't use a var before it is created (a var is what def creates)

Daniel Östling18:05:10

Hum, so order of defn matters, which is why it worked in Cider.


yes, if you run things in a repl in a different order than in a file you will get different results

Daniel Östling18:05:45

I think I have muscle memory to compile whole file in emacs/cider.

Daniel Östling18:05:26

Well, I did say I did something stupid 🙂


the other reason compiling the whole file likely worked is because dumping code into a repl over and over is not "clean"


state carries over, including previous definitions

Daniel Östling18:05:53

Yes, like common lisp/slime.

Daniel Östling18:05:12

Well okay, that's a lesson then. Thank you 🙂

Daniel Östling18:05:34

Also, what style guide are people using or is pretty mixed?


What's the easiest way to convert something like [:S [:ga-jar hakujo] [:verb iku]] to a map with the same keys?


there are three top level forms in there. what would the output be in your mind?


good point, I would like to discard the :S and keep

{:ga-jar "hakujo :verb "iku"}


(into {} (rest c))


that only works with vectors though, not lists


Hello everyone any easy way to get a random item from a hash-set ?


(first (random-sample 0.5 #{"a" "b" "c" "d" "e"}))


but there is a chance that this returns nothing at all ?


I would use (rand-nth (vec s)) *edit - changed from seq to vec because the time-complexity of rand-nth is tied to the time-complexity of the collection


I wonder if there's a cheaper way to get an ILookup sequential from a set...


seems way way better than what i came up with


in spec, if you use a set as a generator, it will pick a random item, might be worth looking up what it does


(when-not (first (random-sample 0.5 #{"a" "b" "c" "d" "e"})) "c")


ohhh completely forgot the spec way of doing it


oh yeah you could just use spec and gen directly if you already use those :D


i already used this in my project, but i forgot


I'd like to recursively smash something like [:ga-jar [:no-jar hakujo] [:no-jar gakkou] sensei] to become

[:ga-jar "sensei of the gakkou of the hakujo"] 
but I'm not really sure how to consume subvecs this way.


@sova a description of the rule might be more helpful than a single example


depending on the rules, you could use reduce on the vector, or (rseq v) to build the string


Cool! Yeah, basically I want to analyze a vector and if it has any collection of subvecs labeled :no-jar I want to read from the end and join them all with "of the" in reverse order.


(->> '[:ga-jar [:no-jar hakujo] [:no-jar gakkou] sensei]
     (keep (fn [t]
             (when (and (coll? t)
                        (= (first t) :no-jar))
               (second t))))
     (reduce (fn [sb e]
           (.append sb " of the ")
           (.append sb e))
" of the gakkou of the hakujo" 


it's slightly easier to read if you use str instead of StringBuilder / .append


You're an amazing wizard


not really - the building blocks in clojure are powerful, it just takes some practice to learn them


and in well written code, the blocks and what they each do should be clear


It's really cool, I don't get how it works exactly. When the key is :no-jar, keep the val... and it appends them in reverse order?


rseq is the efficient way to reverse a vector


oh (rseq) does that I presume. Thread-thru..


keep is just like map, but it throws away nils


so it's like map + filter in one


Cool cool. Hmm. This is very good. I have other blocks that may or may not need this logic, I have to figure out how to work this into my rule set


and the reduce call uses the StringBuilder to construct the result as it sees the inputs


sometimes it helps to write them separately and then make the parts that look similar identical, until you find things that can just be merged / reused


@noisesmith Reading the Java docs, StringBuilder can be faster, but from a simplicity standpoint and if performance is not critical, maybe we can just concat strings instead? (str str-1 str-2) etc


@raspasov yeah, that's true, using str does lead to slightly simpler code in the reduce


that part becomes

(reduce (fn [s e]
          (str s " of the " e))
then you don't need the final str call

👍 4

Yea, either way not a huge difference 🙂 just more of a “pure” Clojure approach


Still need to keep the very last element of the vector


yeah - I literally followed the behavior you described rather than guessing rules to construct your example result


makes sense to add a new conditional to (when ) ?


you might need some sort of polymorphism around the handling of elements - where you need different combining rules / different extraction rules for each one


so instead of using keep before reduce, you'd use a cond or multimethod inside the reducing function to handle each case


and you might also need to keep track of the previous rule / previous token for some rules...


I have some simple rules figured out, but a couple of them can be recursive and it's not clear how to do vector surgery quite yet, but what you have said so far helps quite a bit


one pattern if you always need to see the previous token: (partition 2 1 (cons ::empty coll))


where ::empty could be nil, or any other preferred indicator that there's no "previous" item for that input


neat pattern, not sure what it means


user=> (partition 2 1 (cons ::empty '[:ga-jar [:no-jar hakujo] [:no-jar gakkou] sensei]))
((:user/empty :ga-jar) (:ga-jar [:no-jar hakujo]) ([:no-jar hakujo] [:no-jar gakkou]) ([:no-jar gakkou] sensei))
you end up with a collection of pairs, each one is the previous item, followed by current


ohh neat. partition size 2 step 1


right, and using cons to prefix, to signify that the first item doesn't have a previous item


if you need 4 tokens at a time to know the true context, instead of 2, you could use (partition 4 1 (concat [::empty ::empty ::empty] coll)) - the rule being that for partition of size N you need N-1 empty elements to accurately represent the state


@sova I would say, if an algorithm is becoming too complex, it might be worth re-examining the shape of the data structure you’re dealing with and if there’s a way to structure your data to make your life easier in the first place


There was a quote by someone, not sure who, but basically it said something like “figure out your data structure and then the algorithm is trivial”


that's a good point, I can render it to a nested map structure, but I feel like it's more or less the same acrobatics. Maybe not.


Yea… nested map can probably help… when I start reaching for things like “previous/next” data via (partition … etc) or some sort of reduce, it’s a sign that there’s too much acrobatics 🙂


Hmm. I wonder if the output of instaparse can be flattened rather than nested. If it can be flattened with a rule it would save me a lot of brain.


Right on, yeah it's easier when the drawers are labeled


What does that output look like?


The current output is a nested vector, [:S [:ni-jar gakkou] [:verb iku]] the map output is quite verbose, but it has everything associated perfectly {:content ({:tag :ga-jar, :content (hakujo)} {:tag :wo-jar, :content (kasa)} {:tag :verb, :content (ageru)})} Not sure why it decided to put parens around all the terms...


(those are not identical datas)


parens is probably because it’s a sequence, not a vector


So it's passable to use the vectors for simple stuff, but then I wanted to handle some nested types, which just get smooshed with string concatenation really,


I'm going to politely disagree with @raspasov here. If you want to visit each element of a sequential input in order to build a result, reduce is precisely what you want. If the combining rule is effected by the previous item, you either want to use pairs to track each item's previous, or hold that as part of the accumulated state. Neither of these are signs of problems.


@noisesmith fair 🙂 I won’t disagree; it was more of a general observation; I don’t have a full grasp of the data shape/problem we’re dealing with here


Here's a concrete example


input: [:S [:ga-jar [:no-jar gakkou] [:no-jar sensei] hanashi] [:verb sabishii]] desired result: [:S [:ga-jar "hanashi of the sensei of the gakkou"] [:verb "sabishii"]]


@sova can you paste an example of where we won’t be doing the transformation? Or we always have the :no-jar tag?


no transform required: [:S [:ga-jar hakujo] [:ni-jar sensei] [:wo-jar question] [:verb kiku]]


 [:ga-jar [:no-jar gakkou] [:no-jar sensei] hanashi]
 [:verb sabishii]]
;no transform
 [:ga-jar hakujo] 
 [:ni-jar sensei] 
 [:wo-jar question] 
 [:verb kiku]]


Is that correct?


(split by line so it’s easier to look at)


Essentially any vector that has more than two elements [:key and val] needs to be smashed to have just key and val.


It's a fun puzzle. Recursive ish


And they can be arbitrarily nested ?


Or that’s the deepest they go?


that is actually the deepest they go.


there could be many [:no-jar vecs] but all that depth