This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-05-27
Channels
- # admin-announcements (1)
- # announcements (1)
- # babashka (16)
- # beginners (222)
- # bristol-clojurians (6)
- # calva (13)
- # cestmeetup (5)
- # cider (19)
- # cljs-dev (2)
- # cljsrn (4)
- # clojure (65)
- # clojure-europe (31)
- # clojure-nl (1)
- # clojure-norway (1)
- # clojure-uk (33)
- # clojurescript (64)
- # community-development (5)
- # core-async (18)
- # cursive (15)
- # datomic (6)
- # devcards (1)
- # emacs (18)
- # figwheel-main (102)
- # fulcro (51)
- # graalvm (2)
- # helix (8)
- # instaparse (33)
- # jobs (8)
- # jobs-discuss (3)
- # leiningen (42)
- # off-topic (88)
- # pedestal (15)
- # re-frame (18)
- # reagent (26)
- # reitit (15)
- # rum (3)
- # shadow-cljs (119)
- # spacemacs (9)
- # sql (2)
- # tools-deps (7)
it should look something like
(fn [f] (fn [req] (update-in (f req) [:cookies] conj "whatever")))
(defn- wrap-jwt-payload
[request]
(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))
(jwt/jwt-cookie))))))
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
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
It's confusing to call it wrap-...
then...
Cookies needs to be set in the response, and that function does it's update in on the passed in request
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).
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
[handler]
(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?
@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 :)
no, only :deps
, :paths
, :aliases
and provider-specific keys (as :mvn/repos
) supported as a top-level keys in deps.edn
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.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?
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! 👼
@UK0810AQ2 Yes: monitoring (dashboard), reprioritization of jobs whilst running, and probably more neat stuff I have not thought of yet.
@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.
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
Asked a new, simplified and more general q right now :)
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
(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)))
acc)))
something like this should workthe 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
user/foo
if the symbol can’t be resolved, then it will just use the current namespace
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 originatinghmm 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 onesif you already inside a syntax quote, you can usually use a plain quote instead of adding another layer of syntax quoting
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
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): https://github.com/alidlo/rewrap if there’s a better way of getting to “macros -> code” I’d love to know
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
do you have an example of how you use the interned variables?
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
@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
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}))))
@alidcastano for clj-kondo you want to use some configuration for unknown macros. the relevant docs: - https://github.com/borkdude/clj-kondo/blob/master/doc/config.md#lint-a-custom-macro-like-a-built-in-macro - https://github.com/borkdude/clj-kondo/blob/master/doc/config.md#exclude-unresolved-symbols-from-being-reported
thanks @borkdude will take a look. though tbh I didn’t mind manually adding the '
to the symbol
@alidcastano hiredman is right. if you quote the symbol, the macro will see (quote a)
instead of a
.
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.
You have to deref your atom like this:
(def my-atom (atom ["one" "word" "two" "blurred"]))
(clojure.string/join " " @my-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%
thanks hiredman, I am derefing it with @ though.
output: ["はくじょ" "が" "きく"]
what i doin: (.log js/console (str/join @stale-stack-jp))
Ah. Thanks. How can I ensure I'm not appending new vectors?
@alidcastano, going back to your question. I think you want something like:
(defmacro intern-comps [sym tags]
`(do
~@(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]))
(do
(clojure.core/defn
View
[args__106650__auto__]
(.apply
react/createElement
nil
(clj->js
(clojure.core/into
[(js-module* rn View)]
args__106650__auto__)))))
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
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/$})
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
I was using conj, moving to concat seems to have done the trick
Hello, I've done something stupid and I can't figure it out 🙂
I get a strange ns scoping error, like this:
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).
Code is:
(ns mvp-test.core
(:gen-class)
(:require [instaparse.core :as insta]))
(defn do-parse
[line]
(parse-line line))
(def parse-line
(insta/parser
"logline = #'.*'"))
(defn -main
[& args]
(when (empty? args)
(do
(println "Need line to parse")
(System/exit 1)))
(let [line (first args)]
(do-parse line)))
And build.boot is
Hum, so order of defn matters, which is why it worked in Cider.
Eh, def
yes, if you run things in a repl in a different order than in a file you will get different results
I think I have muscle memory to compile whole file in emacs/cider.
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"
Yeah...
Yes, like common lisp/slime.
Well okay, that's a lesson then. Thank you 🙂
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?
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
Amazin'!
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 ?
yes...
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
damn, thanks
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]
(rseq)
(keep (fn [t]
(when (and (coll? t)
(= (first t) :no-jar))
(second t))))
(reduce (fn [sb e]
(.append sb " of the ")
(.append sb e))
(StringBuilder.))
(str))
" 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
callStill 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...
Yeah...
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 currentohh 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
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)
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]]
;transform
[:S
[:ga-jar [:no-jar gakkou] [:no-jar sensei] hanashi]
[:verb sabishii]]
;no transform
[:S
[:ga-jar hakujo]
[:ni-jar sensei]
[:wo-jar question]
[:verb kiku]]
yep exactly
Essentially any vector that has more than two elements [:key and val] needs to be smashed to have just key and val.
smash = reduce?
It's a fun puzzle. Recursive ish
that is actually the deepest they go.
there could be many [:no-jar vecs] but all that depth