Fork me on GitHub
#beginners
<
2020-06-09
>
matt.wistrand00:06:59

I’m incorporating Integrant into a side project, and I’m wondering if it’s common to put all of the init-key and halt-key! multimethods in the same file, or if folks more often break up those declarations into multiple files and rely on side-effectful imports to ensure the system is composed properly?

phil63407:06:42

Hi. Has anyone got suggestions for introductory hands-on Clojurescript material. Recent enough that it's not going to collapse in a muddle of broken dependencies and with enough context that you don't have to be thoroughly conversant with the modern JS ecosystem to know what's going on?

thegobinath09:06:27

Looking for good learning resources for Clojurescript+Re-frame/Reagent!

thegobinath09:06:27

Looking for good learning resources for Clojurescript+Re-frame/Reagent!

jimka.issy10:06:36

What is the correct way to write tests for function which are defined using memoize .? Before testing a function, my test case would often like to erase the cache.

jimka.issy10:06:36

What is the correct way to write tests for function which are defined using memoize .? Before testing a function, my test case would often like to erase the cache.

michael.e.loughlin11:06:02

There's no way to clear the memoize cache, you may only define a new memoized version One way of implementing it is to define your pure un-memoized function (defn f* [] ...) and then create a memoized version (def f (memoize f*)) Yes, this will use a load of memory.

michael.e.loughlin11:06:51

It's recommended to use a different type of cache if memoize doesn't fit your performance requirements

jkrasnay11:06:17

You can just create a memoized version in a let form for the duration of your test:

(let [f (memoize f*)]
  ; test f here
  )

jimka.issy13:06:52

if I memoize a function which is already memoized, does that work? when the let finishes, is the old cache restored. Sorry, I don't really know how atoms work.

jimka.issy13:06:05

It is not just a question of directly testing memoized functions. one of my low level functions is memoized, but I need to test the api functions. They effectively rely on the memoized data. I'd like to test those api functions independently of the current state of the cache.

jimka.issy13:06:01

can I do something like

(binding [f (memoize f)] ...)

jimka.issy13:06:39

so that low level calls to f not explicitly mentioned in my tests, will use the dynamically bound f

jkrasnay13:06:44

Like most things in Clojure, memoize doesn’t change the function its given, it returns a new function, so yes, the original unmemoized function continues to exist in its original state.

jkrasnay13:06:19

I believe your binding solution will work. You just have to declare f as ^:dynamic

jimka.issy13:06:04

hmm. so for memoize functions to be testable, they need to be dynamic.

michael.e.loughlin14:06:38

Since memoize makes the pure function stateful, you could pass the memoized function as a parameter. What aspect are you testing?

jimka.issy14:06:06

I explained before, but again: one of my lowest level functions (the work horse) is implemented with memoize. I want to test the API functions which don't call this low level function explicitly. But since the value is memoized, the tests only test according to the current state of VM. I'd like the test cases each to assume there's no cache. That seems to me like a much safer test.

michael.e.loughlin14:06:29

IMO only if I was testing caching performance and needed control over that, in which case maybe memoize is not the right tool to use. You're either unit testing the underlying function, or testing the stateful caching aspect. The reason I say that is because memoize expects a referentially transparent function, so I think it's fair to say there's a decent guarantee that what you get out is what you put in. I don't think there's a reason not to add ^:dynamic to the fn for tests, but I don't see a huge reason to do it either I'm working off of information in Clojure: The Essential Reference from Manning and (source memoize)

michael.e.loughlin14:06:24

It seems like a judgement call 🙈

jimka.issy15:06:04

suppose the function you are memoizing calls some other function. and in the mean time (in the live session) you edit that other function. Now when you run your tests, is the information cached from v1 or v2 of that other function? Even if it is referentially transparent, functions can be edited while you are editing. This means it is likely that you'll get different results from testing in your live session vs testing in stand-alone.

jimka.issy15:06:50

Basically memoizing is side-effectful computation, which makes it difficult to test.

michael.e.loughlin16:06:03

Fair point about redefinitions in the REPL

vachichng10:06:52

hi everyone, is there an open source project that uses datomic in extense where I could study its code?

vachichng10:06:52

hi everyone, is there an open source project that uses datomic in extense where I could study its code?

a.grison11:06:12

Did you take a look at this repository: https://github.com/Datomic/mbrainz-sample

vachichng11:06:55

Thanks, I will take a look at it

amirali.sadeghloo12:06:50

Hi guys.I want to iterate over a nested vector and delete some elements (for example deletes "5" whenever finds it) and I want to use reduce / transducer instead of nested loop (unlike imperative systems). I do understand that the answer isnt nested loop recur. so i went for reduce/transdures but my code fails each time. Can u give me an example of doing so?

amirali.sadeghloo12:06:50

Hi guys.I want to iterate over a nested vector and delete some elements (for example deletes "5" whenever finds it) and I want to use reduce / transducer instead of nested loop (unlike imperative systems). I do understand that the answer isnt nested loop recur. so i went for reduce/transdures but my code fails each time. Can u give me an example of doing so?

prashrathod713:06:47

@ (clojure.walk/postwalk #(if-not (and (coll? %) (seq %)) (* 10 %) %) [[1 10] [2 10]]) This is using Clojure.walk and not reduce, also can you post here what you are trying so that we can check if we can fix it.

mmakgaba13:06:07

Trying to make start a repl this error. Run a project

mmakgaba13:06:25

Could not locate cognitect/rebl__init.class

mmakgaba13:06:49

Caused by: .FileNotFoundException: Could not locate cognitect/rebl__init.class, cognitect/rebl.clj or cognitect/rebl.cljc on classpath.

mmakgaba13:06:03

What am I missing?

alexmiller13:06:16

not sure what you're doing

alexmiller13:06:26

what do you mean by "make rebl"

mmakgaba13:06:09

Trying to make start a repl this error. Run a project

alexmiller13:06:04

the error is saying that you're trying to run rebl, but rebl is not on the classpath. but I'm not sure what you're doing so I don't know how to help

mmakgaba13:06:47

How do I add rebl to my class path than?

alexmiller13:06:53

there are some wiki pages with more info on other envs https://github.com/cognitect-labs/REBL-distro/wiki

mmakgaba13:06:22

Ahh, I see what the issue is. Thank you

maik.wild13:06:01

Hi, I have been working with clojure fixtures. I am running a test and take a screenshot at the end, everything working fine. My question is, is there a way to get the name of the function in the fixture? I want to use it as the file name of the screenshot. Code:

(defn fixture-selenium
  [f]
  (try
    ;; setup here
    (f)
  (finally
    (println f) ;; Prints cider.nrepl.middleware.test$test_vars$fn__38755$fn__38760
    (save-screenshot)))

maik.wild13:06:01

Hi, I have been working with clojure fixtures. I am running a test and take a screenshot at the end, everything working fine. My question is, is there a way to get the name of the function in the fixture? I want to use it as the file name of the screenshot. Code:

(defn fixture-selenium
  [f]
  (try
    ;; setup here
    (f)
  (finally
    (println f) ;; Prints cider.nrepl.middleware.test$test_vars$fn__38755$fn__38760
    (save-screenshot)))

maik.wild13:06:02

I tried (meta f), but meta info is nil

gandhiromit7714:06:12

Currently whenever I add new query in queries.sql , I have to close and reopen REPL everytime to test it. I have also tried to reload in the REPL using (use '[demo.db.core :as db] :reload-all) but it didn't work. Currently I'm using Calva plugin in VS Code. So is there any way to test it without closing and reopening REPL everytime ?

gandhiromit7714:06:12

Currently whenever I add new query in queries.sql , I have to close and reopen REPL everytime to test it. I have also tried to reload in the REPL using (use '[demo.db.core :as db] :reload-all) but it didn't work. Currently I'm using Calva plugin in VS Code. So is there any way to test it without closing and reopening REPL everytime ?

iagwanderson14:06:20

Are you using hugsql to read the queries.sql file?

iagwanderson14:06:08

The only thing I do is to reload the namespace where hugsql/def-db-fns importing the file is used.

gandhiromit7714:06:32

I tried to reload the db.core namespace but it didn't reflect the new changes.

iagwanderson15:06:15

can you share more code of your db.core namespace?

gandhiromit7715:06:18

I followed the same question of stack overflow and used use as well as require but nothing worked, even I tried to reload using Calva plugin shortcut but nothing worked.

gandhiromit7715:06:51

(conman/bind-connection *db* "sql/queries.sql") , using this way I'm getting queries.sql file.

gandhiromit7715:06:00

This is the file, it is default code of luminus framework.

dharrigan15:06:04

I seem to recall a trick, discussed a while ago that involved some sort of compliation of the code during startup/repl? I can't recall. @alexmiller I think you mentioned it?

dharrigan15:06:55

thank you dan 🙂

readyready1572816:06:13

I'm still trying to figure out the purpose of dynamic variables when let exists

readyready1572816:06:49

What is the use case here

alexmiller16:06:07

dynamic vars let you pass context down the call stack but not as parameters

readyready1572816:06:22

Oh so it's just dynamic scope then?

alexmiller16:06:40

generally, you should avoid dynamic variables imo - usually it's better to make that stuff explicit in the call

readyready1572816:06:37

That's an ... interesting feature

jimka.issy16:06:14

dynamic variables are very powerful, but with power comes responsibility.

kbosompem17:06:37

what is the right away to share global variables in clojure. e.g i have 3 different namespaces with ring routes and I want to pass db information

kbosompem17:06:01

Another namespace with those variables ?

hiredman17:06:09

Don't make globals, pass arguments

hiredman17:06:09

A common way to pass extra stuff to ring handlers is middleware that assocs that stuff into the request map

kbosompem18:06:24

so i'm using the environ library to hold db information

kbosompem18:06:42

but not sure how to pass it to each route without calling it each time

kbosompem18:06:42

but not sure how to pass it to each route without calling it each time

smith.adriane18:06:10

without calling what each time?

kbosompem18:06:47

yep see Yogthos example here https://yogthos.net/posts/2015-10-01-Compojure-API.html he repeats (:db config) in each route

smith.adriane18:06:35

it looks like the responses are written in-line in this example. for that particular use case, repeating (:db config) seems reasonable. if your views are defined elsewhere, then you can have middleware provide the db for each route

vachichng20:06:02

you could create a dynamic var and bind it in a ring middleware when a request arrives

dharrigan18:06:52

I pass "configuration" as a map (usually I leave it the in last position, if a reasonable n-arity is required)

dharrigan18:06:29

I also use juxt clip to manage some state, like a shared database connection, or a redis connection. That state is held in the map and passed around.

iagwanderson18:06:41

you guys tried aero ? I just noticed that I am not using leiningen profiles to decide which aero #profile to choose. I have (read-config "config.edn" (System/getenv "PROFILE")) ... someone knows if you can use the profiles passed as lein with-profile PROFILE and catch that value to be used in aero?

iagwanderson18:06:41

you guys tried aero ? I just noticed that I am not using leiningen profiles to decide which aero #profile to choose. I have (read-config "config.edn" (System/getenv "PROFILE")) ... someone knows if you can use the profiles passed as lein with-profile PROFILE and catch that value to be used in aero?

dev-hartmann22:06:51

I think the with profile will either be passed as an argument to the application on startup

dev-hartmann22:06:45

like one of the jvm switches -Dprofile test

dev-hartmann22:06:16

this might be of help

dev-hartmann22:06:41

Great, so why is this more useful? The big benefit I've discovered is the .lein-env file in the root of my project. This file holds a map of environment values that can be useful during development. There are 2 ways to create this file.

The RIGHT way as set out by the creator of the project, and,
The WRONG way as in how I use it
environ also has a plugin available lein-environ which sucks profile specific settings from ~/.lein/profiles.clj and/or a project specific profiles.clj (which should not be checked into source) and creates the .lein-env file when Leiningen does its thing (effectively making .lein-env a transient file). A .lein-env file looks a little something like this.

dev-hartmann22:06:06

excerpt from the above article

dharrigan18:06:49

Yes, I use aero extensively

dharrigan18:06:58

It's part of my juxt clip setup 🙂

dharrigan18:06:12

But I don't use lein, I'm a deps guy 🙂

iagwanderson18:06:51

ouch =/ this app is a bit old now, I was happy with leiningen and decided to leave this way rsrs

iagwanderson18:06:51

ouch =/ this app is a bit old now, I was happy with leiningen and decided to leave this way rsrs

dharrigan18:06:39

Perhaps if you ask in #juxt channel, you may get an answer?

iagwanderson18:06:48

Good idea, thanks

joao.micena22:06:17

Hi all! I am trying to understand how to use the component library from Stuart Sierra, but I am struggling to understand the record part. In the example, he creates a record using (defrecord Database), and then a constructor using map->Database. My doubt is: What exactly this map-> is doing? Is it mutating the Database record? How it was created? Thank you in advance!

seancorfield22:06:11

@joao.micena When you use (defrecord Foo), Clojure automatically generates two constructor functions for you: map->Foo that accepts a regular hash map and returns a Foo record populated from the hash map and ->Foo that accepts positional parameters matching the fields you declared in defrecord (and returns a populated record).

seancorfield22:06:32

Records -- like other Clojure data structures -- are immutable.

seancorfield22:06:06

user=> (defrecord Foo [a b])
user.Foo
user=> (->Foo 1 "Two")
#user.Foo{:a 1, :b "Two"}
user=> (map->Foo {:a "One" :b 2})
#user.Foo{:a "One", :b 2}
user=> 

joao.micena23:06:23

Hmmm I see, this helps a lot, thank you! By the way, I am also using your usermanager-example repo and it has been really helpful!