Fork me on GitHub
#clojure
<
2021-08-20
>
Richard Bowen00:08:00

Hey, are there any ready made cookie-based user authentication options available for Clojure?

emccue00:08:38

take a look at buddy and co

Richard Bowen01:08:54

what is the and co?

kwladyka11:08:51

It was quite a long time ago, but I got to the conclusion if want to have it good write it yourself

kwladyka11:08:02

I didn’t find anything what satisfy me

kwladyka11:08:14

But I don’t really remember details

Edward Hughes11:08:48

Hi there, has anyone ever had trouble picking up POI on the classpath while working with Docjure? Deps are installed, so I can't see why it's not able to be loaded.

vemv19:08:00

I haven't had that error w/ Docjure myself what does the stacktrace look like?

noisesmith17:08:20

typically with clojure we don't install deps, we use a dependency manager which caches deps and calculates a classpath including the cached artifact

noisesmith17:08:19

if you literally mean installing the dep (eg. via OS package manager) I have not successfully used debian installed java libraries with clojure, and it always ends up being easier to use the dep manager (eg. clj or lein) to add the dep

vsvn13:08:38

Any suggestions on how to write better E2E tests?

djblue15:08:24

One of the interesting things I've seen with e2e tests is allowing the driver to inspect the client state directly to make assertions and drive the tests.

djblue15:08:49

Pulling the client side state in our app is as easy as

(defn- get-state [driver]
  (read-string
   (api/js-execute driver "return window.getState()")))

djblue15:08:02

We've been using https://github.com/igrishaev/etaoin at work and it seems to work pretty well.

vsvn17:08:33

interesting, thank you! Ill try it out.

lilactown17:08:20

I've got an interesting algorithm I'm trying to convert into Clojure. the algorithm is constructing a graph. I want to be able to stop and resume constructing the graph at any leaf. the way I'm reading it done in the mutable lang (JS) is by keeping two top-level references: the root of the graph and the node to be worked on. it then mutates properties on these nodes to keep references to their parent, child and siblings as they do work to form the graph.

lilactown17:08:12

I'm trying to figure out if there's a clever way to handle this in an immutable way before I resort to a bunch of ref types or using mutable fields :<

lilactown17:08:21

it kind of feels like a zipper but I've only ever used a zipper to search and modify leaves, not construct an entire tree starting from the root

p-himik17:08:45

It still won't save you form mutating data if you need to pause and resume processing on the very same data. But if you can change the reference to the data like you'd do with regular assoc, you can do what JS does, in pretty much the same way, no?

lilactown17:08:02

the reference identity isn't important but what I'm stuck on is trying to imagine what kind of structure would allow me to stop and resume it

lilactown17:08:40

I guess I have to keep track of where in the tree I'm currently working on

lilactown17:08:50

which is why it seems like a zipper

phronmophobic17:08:37

you can definitely do this with zipper.

p-himik17:08:19

It's not a tree, it's a graph, so just having reversed or two-way references won't work if the path is important. You need to record the path. A zipper is indeed fine. But if any branch within a node can be identified with a single unique key, then just a vector of such keys will work as well.

lilactown17:08:54

I'm going down the zipper route

phronmophobic17:08:55

you could also use any of the graph libraries like ubergraph/loom

phronmophobic17:08:57

not sure if your graph will have cycles, but if it does, it seems like using zippers would be cumbersome

lilactown17:08:04

I say graph but I'm p sure it's a tree, so zippers should be ok

lilactown17:08:09

they just confuse me 😅

p-himik17:08:09

So, why not just a vector path? Something like [:a :b :c] for a tree that's just {:a {:b {:c 1} :d 2} :e 3}?

lilactown18:08:18

I think that's basically what zippers do they just have more algebra already done for you

p-himik18:08:49

Not sure what's mean by algebra here. They don't have anything that's not simple up/down/left/right navigation with some mutation. If your tree doesn't have a concept of left and right siblings, then zippers won't be a good fit IMO. In the above toy tree, that's exactly the case. What's the path "down from :a"? There's no such thing. What's the path "to the left of :d"? Again - no such thing. But if your tree is more similar to a nested vector, then zippers might be more suitable. Although vectors are still associative, you can store a vector of indices as path.

phronmophobic18:08:30

> They don't have anything that's not simple up/down/left/right navigation with some mutation. zippers are immutable

lread18:08:42

FWIW, I did include some https://cljdoc.org/d/rewrite-clj/rewrite-clj/1.0.644-alpha/doc/user-guide#_a_brief_introduction_to_zippers in rewrite-clj user guide - if that helps your zipper journey at all.

2
phronmophobic18:08:23

> What's the path "down from `:a`"? There's no such thing. it's easy to define a zipper navigation that does exactly this

p-himik18:08:04

> zippers are immutable That's just poor wording on my end. I mean that there are things like assoc but for zippers.

lilactown18:08:42

I understand what you mean p-himik. In my case, my tree has left and right siblings. to show my hand, it's a React fiber tree - so fibers that represent elements on the page have quite a bit of metadata about them and have siblings, children, etc. I'm guessing if I go about trying to do the book keeping myself, I'm going to end up recreating zippers from scratch - which would probably help me understand them more, but I want to be lazy on my three day weekend 😛 so I'm going to try and grok zippers a bit better first.

👍 2
hiredman19:08:15

If zippers don't work out, try some kind of lenses, you can often get something very zipper like but a little more customizable

lilactown19:08:16

zippers are working really well so far

phronmophobic20:08:43

it looks like reconcile-node could probably be simplified to:

(zip/edit loc perform-work)

lilactown21:08:50

ah good tip. I've added more to it now, but I could probably move that into perform-work

lilactown22:08:35

having gone down the zipper route, I am now wishing that zippers had a built-in way to maintain some information in the context as it traversed the tree

phronmophobic23:08:04

per node context? or just general context?

lilactown23:08:05

general context

phronmophobic00:08:22

I tend to use the zipper operations as low level ops and use them to create higher levels ops that more directly fit my use case.

ghadi23:08:31

Is the flow of information/context Root-> leaves Leaves-> root Or bidirectional ? @lilactown

ghadi23:08:48

Or is it about building the tree itself

lilactown23:08:10

it's about building the tree itself. I have some config that would change how the tree is constructed, and I'd like it to be associated with the in-progress tree I'm constructing with a zipper

lilactown23:08:48

I guess for now I'll keep a bookmark:

{:config <config>
 :wip-tree <zipper>}
and if I come back later I can pass that to a function that will thread config through to the functions used to build the tree

simongray07:08:11

Can you put it in the metadata of the zipper when you iterate through the nodes?

simongray07:08:23

Depends a lot on your algorithm of course, but I think I’ve dones something like that. My use case was modifying an existing tree, though.

emccue23:08:53

Pattern we just started adopting but we are pretty confident is going to start paying dividends

emccue23:08:16

make a file for assumptions we make about our data model that aren't necessarily apparent in our data model

emccue23:08:00

like 1-1 relations assumed in a 1-many sql relation

emccue23:08:16

(ns your.company.domain.assumptions)

(def one-cart-per-horse ::one-cart-per-horse)

emccue23:08:34

then attach assumptions to vars directly as metadata

emccue23:08:51

(defn ^{:assumes #{assumptions/one-cart-per-horse}}
  function-that-we-would-have-to-search-for-otherwise
  [cart-id]
  (first (p-horses/for-cart-id cart-id)))

emccue23:08:26

with the hypothetical benefit that when refactoring code later this will be easier to track down than a text comment