Fork me on GitHub
#beginners
<
2022-04-24
>
dbsgtk02:04:16

I would like to to use a letfn in a function definition, but I want the function definition to have two arities. I want them to share the same letfn. What is the idiomatic way to do this? Currently I have the letfn in the outer form, and then the defn with the two arities inside.

hiredman02:04:08

Writer a helper function, have the left in there, have both arities just call the helper

🙏 1
dbsgtk02:04:47

(letfn [(rand-str [len]
          (str/lower-case (apply str (take len (repeatedly #(char (+ (rand 26) 65)))))))]
  (defn gen-n-keys
    "Generate a set of n unique keys (namespaced or not)"
    ([n]
     (map #(keyword %)
          (take n (set (take (* 2 n) (repeatedly #(rand-str (/ n 2))))))))
    ([ns n]
     (map #(keyword ns %)
          (take n (set (take (* 2 n) (repeatedly #(rand-str (/ n 2))))))))))

(gen-n-keys 8)

(gen-n-keys "foo" 8)

dbsgtk02:04:16

Like that?

dbsgtk02:04:38

It seems like a kludge

hiredman02:04:19

Have arity 1 call arity 2 with nil for the ns

dbsgtk02:04:56

D'oh! Thanks homerdisappear

dbsgtk02:04:16

Is the letfn in the outer form still the idomatic way to approach it?

hiredman02:04:46

Depends, I am not a huge fan, and would prefer just making letfns like that defns

hiredman02:04:39

But I am also a bigger fan of letfn than a lot of people are

dbsgtk02:04:42

i see. I just realised I can keep the letfn with the 2-arity. Thanks for the help!

(defn gen-n-keys
    "Generate a set of n unique keys (namespaced or not)"
     ([ns n]
      (letfn [(rand-str [len]
                (str/lower-case (apply str (take len (repeatedly #(char (+ (rand 26) 65)))))))]
        (map #(keyword ns %)
             (take n (set (take (* 2 n) (repeatedly #(rand-str (/ n 2)))))))))
    ([n]
     (gen-n-keys nil n))
    )

mister_m04:04:46

I've got some ring middleware that attaches a trace id on my request object. I'd like to include the trace id in any logging I do while execution is in my little API's handlers. https://github.com/ptaoussanis/timbre`timbre`https://github.com/ptaoussanis/timbre and I am vaguely aware that it allows middleware, which would be good for adding this trace id to my logs, however I am not understanding how I would modify timbre to provide this trace-id augmented logging. Ideally (I think?) I'd just have timbre middleware that would modify my timbre logger to include the trace id info instead of me adding it to my request and passing that around. Curious if anyone knows how I'd do that.

mister_m04:04:55

Or is there a non-middleware way to provide this trace id to timbre in for the lifetime of a request in a handler? I am not very clear on what timbre's logging *context* is, perhaps that could help ?

Mobe10:04:05

I’m looking into oauth2 libraries. Should I be using https://github.com/weavejester/ring-oauth2 or https://github.com/threatgrid/ring-jwt-middleware ? It just needs to support the Client Credentials Grant flow and jwt. Ok I see it now… so ring.jwt runs on top of ring as middleware?

teodorlu12:04:47

I haven't used the libraries you're referring too. But: • If you want to use Ring, you probably want to use a ring middleware for oauth. • James Reeves (weavejester) wrote ring, so his middleware may be a good place to start.

1
practicalli-johnny12:04:33

I used https://github.com/kelveden/ring-jwt with Reitit and ring handlers / middleware. I assume it will work the same with any ring middleware I can dig out the code if interested.

Mobe16:04:07

@U05254DQM that would be truly helpful if you could share some code thank you. never mind. github search will do https://github.com/search?q=ring-jwt++extension%3Aclj

practicalli-johnny10:04:18

@U03D0A0A95F the github docs were pretty good as I recall. I've hacked out some of the key code sections from the project I worked on into this Gist, if its of any use https://gist.github.com/practicalli-john/ec62c3c02aa6b18ebb9346f96a3c52cc

Mobe20:04:20

Sorry, I was quite busy, work :( I will def look into it out.. In the mean time here is my attempt of using ring-oauth2 https://github.com/kiviuk/clj-backend-baseline/blob/546950b1ca797f07853054568d67e0d191c063ef/src/clj/app/core.clj#L47 I’m getting this error though

java.lang.Thread/run (Thread.java:829)
clj꞉app.core꞉> 
; Evaluating file: core.clj
; Execution error (ExceptionInfo) at reitit.dev.pretty/exception (pretty.cljc:228).
; -- Router creation failed ------------------------------------ reitit.ring:77 --

Don't know how to create ISeq from: ring.middleware.x_headers$wrap_x_header$fn__6220
--------------------------------------------------------------------------------
; Evaluation of file core.clj failed: class clojure.lang.Compiler$CompilerException
and that’s supposed to be the pretty version 🙂 It doesn’t give you any clue to where the error happens other than deep inside the library itself.

Stef Coetzee12:04:40

Is there a recommended stack of libraries (Luminus, Fulcro, etc.) for working with something like https://github.com/tldraw/tldraw, a canvas package written with React, on the front end? Coming from the Rails world, I'm new to the modular, library-based approach to building web applications. Still, there are some benefits to using sane defaults others have pulled together. Thanks for your time! 🙏😁

dumrat14:04:47

On windows. What's the reason for this:

PS D:\work\projects> clj -A:deps -Tnew fbsync
Execution error (FileNotFoundException) at java.io.FileInputStream/open0 (FileInputStream.java:-2).
-Tnew (The system cannot find the file specified)

Full report at:
C:\Users\dumra\AppData\Local\Temp\clojure-730374096325810181.edn

apiology14:04:16

Does the full report it points to have the filename it’s looking for inside? That might provide a hint.

dumrat14:04:11

{:clojure.main/message
 "Execution error (FileNotFoundException) at java.io.FileInputStream/open0 (FileInputStream.java:-2).\r\n-Tnew (The system cannot find the file specified)\r\n",
 :clojure.main/triage
 {:clojure.error/class java.io.FileNotFoundException,
  :clojure.error/line -2,
  :clojure.error/cause
  "-Tnew (The system cannot find the file specified)",
  :clojure.error/symbol java.io.FileInputStream/open0,
  :clojure.error/source "FileInputStream.java",
  :clojure.error/phase :execution},
 :clojure.main/trace
 {:via
  [{:type java.io.FileNotFoundException,
    :message "-Tnew (The system cannot find the file specified)",
    :at [java.io.FileInputStream open0 "FileInputStream.java" -2]}],
  :trace
  [[java.io.FileInputStream open0 "FileInputStream.java" -2]
   [java.io.FileInputStream open "FileInputStream.java" 212]
   [java.io.FileInputStream <init> "FileInputStream.java" 154]
   [java.io.FileInputStream <init> "FileInputStream.java" 109]
   [clojure.lang.Compiler loadFile "Compiler.java" 7571]
   [clojure.main$load_script invokeStatic "main.clj" 475]
   [clojure.main$script_opt invokeStatic "main.clj" 535]
   [clojure.main$script_opt invoke "main.clj" 530]
   [clojure.main$main invokeStatic "main.clj" 664]
   [clojure.main$main doInvoke "main.clj" 616]
   [clojure.lang.RestFn applyTo "RestFn.java" 137]
   [clojure.lang.Var applyTo "Var.java" 705]
   [clojure.main main "main.java" 40]],
  :cause "-Tnew (The system cannot find the file specified)"}}

practicalli-johnny15:04:32

-Tnew is for running a tool called new that was (or maybe it was not) installed on your computer Try calling the tool without the -A:deps alias (I do not believe deps is a good name for an alias as that is built in to the Clojure CLI tool) Maybe if you describe what it is you wish to do, we can help

👍 1
Alex Miller (Clojure team)16:04:07

I think in this case you are using a version of the Clojure tools before there was -T support and it's treating that arg as a script to run

Alex Miller (Clojure team)16:04:17

So you you should update to latest

👍 1
West15:04:52

So I've had some paralysis by analysis for awhile thinking about how to work with databases. I asked myself questions like: Which is the best database? What are best practices with database transactions? What are the pitfalls, foot guns? What is a good query language? How do I design for flexibility? It's all wrong!! I'm content with just having a friggin atom, now let me store that friggin atom on my hard drive instead of a runtime within memory. Simple as that! CRUD? How about assoc, update, and dissoc? Not to mention all the other amazing functions for map manipulation. Is there a simple way to have data structure, that's persistent, without having to glue my map to some SQL table, datomic schema, or graphQL API? By the way, I have no idea how any of those database technologies work, I just know there's some hoops I'm dreading to jump through.

Cora (she/her)16:04:33

I think duratom is one

West16:04:01

Thank you so much! I can't wait to try it out!

💜 1
Cora (she/her)16:04:34

and if you need to go beyond that there are things like datalevin that are a big step up but not exactly as esoteric to set up or maintain as a full out-of-process database https://github.com/juji-io/datalevin

dgb2318:04:12

Often doing the simplest and most minimal thing is just right. Something like duraton seems really attractive for that. The two big implications are that you’re going to do normalization and keeping track of relationships at some point yourself and you need to be able to hold the whole data in memory. But that approach is so lightweight that you should be able to write mappers and adapters for a more sophisticated DB if you then need it.

dgb2318:04:03

Also definitely check if it is safe to make backups of the file db while the application is running.