Fork me on GitHub
#beginners
<
2020-05-22
>
mister_m02:05:08

does anyone have any recs on a test coverage tool for clojure? I'm testing using clojure.test , and looking for a simple breakdown of line and branch covereage a la jacoco.

andy.fingerhut02:05:17

I have not used it, but Cloverage is one existing tool for that: https://github.com/cloverage/cloverage Not sure off hand if there are any others.

mister_m02:05:48

i can already tell I am going to fail to pronounce that 90% of the time

mister_m02:05:07

but worth investigating, thanks

didibus04:05:56

We use cloverage at my work, works well enough

ig0revich07:05:55

Hello. @alexmiller am I right that feature “Maven authenticated repos” (deps.edn) does not support encrypted passwords in ~/.m2/settings.xml? I mean encrypted like this https://maven.apache.org/guides/mini/guide-encryption.html

Alex Miller (Clojure team)12:05:29

Honestly, I am not sure, haven’t tried it. We are going through Maven apis to get that stuff, so it’s possible it would work but something more may be needed

ig0revich13:05:55

I see. I tried settings.xml with encrypted passwords. No luck. It began to work only when I replaced encrypted password with real one.

ig0revich13:05:59

Thank you for reply

Alex Miller (Clojure team)13:05:37

that's good to know, would not be opposed to adding support, but haven't looked at what that would entail

ig0revich13:05:50

Thank you for deps.edn. I just started learning Clojure but I like that I have out from the box tool to resolve dependencies and to build my sandbox projects.

ig0revich13:05:30

With javac without ant and maven it's more complicated for sure)))

ig0revich13:05:05

I mean building java projects without ide

Alex Miller (Clojure team)13:05:55

working on something to plug that hole right now :)

ig0revich13:05:18

wow, great news))

Alex Miller (Clojure team)14:05:38

well that, and a lot of other similar holes :)

Jakob Durstberger07:05:06

Can someone explain to my why the handler in the .catch expression is not valid?

(defn sign-in [credentials]
  (-> (.signIn Auth (clj->js credentials))
      (.then (fn [user] {:result :success :user user})) ;;Works fine - as expected
      (.catch #({:result :error :error %})))) ;;Invalid?
This code throws an invalid arity exception when the catch expression is called

delaguardo07:05:30

(macroexpand '#({:result :error :error %})) ;; => (fn* [p1__30029#] ({:result :error, :error p1__30029#}))

delaguardo07:05:39

instead of a map literal you can use hash-map function. #(hash-map :result :error :error %)

👍 4
Jakob Durstberger07:05:33

So I guess it is because a map literal is not a function?

delaguardo07:05:44

it can be called as a function ({:foo 1} :foo) but map is a function of one or two arguments

delaguardo07:05:14

in your case it will throw ArityException

teodorlu08:05:19

To be clear, map as a function is for looking up values in a map, and not constructing a map.

👍 8
teodorlu08:05:13

(let [f #({:a 1 :b 2} %)]
  [(f :a) (f :b) (:f "random")])
;; => [1 2 nil]

fmn07:05:48

For anyone who uses timbre, is there any way to blacklist a value? Or I have to use :middleware ?

Phil Hunt09:05:46

So I'm trying to create some constants for a noughts and crosses game. In Common Lisp I'd use defparameter for something like that and put asterisks around the symbol. Clojure is complaining and saying I need to mark them ^:dynamic

jsyrjala09:05:26

(def my-constant 1234.123)

jsyrjala09:05:31

Or possibly (defonce my-constant (some-function))

Phil Hunt09:05:03

aha the latter looks like what I need. Thanks 🙂

Olical09:05:49

If there's something asking you to mark them as dynamic, that's probably a linting tool? I saw you mention asterisks in another message. Using asterisks such as *ns* (or, earmuffs as I and a few others like to call them) denotes that this var will be bound by yourself or something else above you. *ns* is ^:dynamic and bound for you. This is just a convention though. Anything telling you to do that is probably just linting, you should only be adding *...* if you plan to rebind that value in some way with something like https://clojuredocs.org/clojure.core/binding

Olical09:05:52

When I want a constant I'll use def, if it's something stateful like the result of starting a server I use defonce, the main difference is removing the *...* will get rid of that warning.

Olical09:05:29

You use defonce for stateful things so that reloading the file won't overwrite your stateful value.

Phil Hunt11:05:39

Got it, thanks 🙂

Phil Hunt11:05:01

I'm using Prelude / Emacs, so linting sounds likely

Olical11:05:44

If I had to guess, it'll be clj-kondo or joker integration. And if you don't have those I'd highly recommend looking into them. They can catch all sorts of common mistakes.

Phil Hunt11:05:54

heh, that just sent me down the Flycheck rabbit hole, thanks for the tip. They look useful.

Phil Hunt11:05:57

First I'm going to try to figure out atoms enough to get the game state functions working properly

Phil Hunt11:05:09

But I'll definitely come back to that

Phil Hunt12:05:18

So the sort of thing you'd use defonce for might be reading a bunch of initial game data from a file?

Olical12:05:12

Mmm, not quite unless I'm misunderstanding. I'd put my game state in an atom held by a defonce: (defonce state (atom initial-state)) This allows you to evaluate the entire buffer with your editor and not worry about resetting the world state. Allowing you to change functions etc without worrying about accidentally resetting the game state. Useful if you're tweaking a render function for a specific state of the game.

Olical12:05:25

Of course you can just evaluate the form you care about and just avoid reevaluating your stateful stuff but sometimes signalling "this thing should persist even as you reload things" helps out other devs too.

Olical12:05:20

You could then have a function called reset-game or something that called (reset! state initial-state) if you wanted to start from the beginning.

Phil Hunt14:05:08

Oh OK, that's very useful (although not for the very simple game I'm basically porting from Lisp)

Phil Hunt14:05:40

But I'm going to try hangman or something after getting noughts and crosses to work

Phil Hunt14:05:16

Actually though, I can use that here too

Phil Hunt14:05:21

yes, thanks !

Phil Hunt14:05:36

I hadn't got that far (still doing the game loop) but I'll definitely want to be able to initialise and reset state

Phil Hunt14:05:51

I was initialising in the repl, but it's better to do it that way

Phil Hunt09:05:18

What's the idiomatic way to do something like this? I just want some simple numerical constants and won't be changing them.

Phil Hunt09:05:07

Is it just def but don't use the asterisks?

💯 4
gon10:05:41

def it's ok

mloughlin10:05:36

values are immutable, so def is OK

Phil Hunt11:05:09

Yep ta. I think it was just following Lisp convention and using * in the name that was causing issues

Phil Hunt11:05:45

and I can kinda understand it, because Clojure (I think) wants to reserve that for when you really do mean dynamic

afleck22:05:52

I am using reagent and cljs-ajax. I want to make multiple GET requests and store the results in an r/atom. My handler for the get request boils down to

(swap! my-atom into)
so I have this get request wrapped in a function load-url that takes a URL as parameters, and to fill up my atom I do
(defn refetch []
  (reset! my-atom nil)
  (map load-url '(list of urls)))
When I call refetch in a figwheel repl, it works perfectly. But if I have a button like
(defn refetch-button
  [:button
    {:on-click (fn [] (refetch))}
    "refetch"])
When I click the button, the atom is reset to nil, but it stays nil and it seems like the get requests are not happening. Can anyone help? I've been pulling my hair out over this for a while.

bhauman22:05:28

its the most common clojure error

bhauman22:05:50

@andrea_fleckenstein it will work in the repl but not in your app

bhauman22:05:00

map is LAZY 🙂

bhauman22:05:28

meaning it won’t execute until its consumed

afleck22:05:03

@bhauman what does "consumed" mean?

bhauman22:05:07

or you can cheat with mapv

Chris O’Donnell22:05:17

There is also run!

bhauman22:05:39

@andrea_fleckenstein consumed means you have to use the map

bhauman22:05:01

the results of the map before they are realized

bhauman22:05:38

its an amazing feature, but takes some getting used to

bhauman22:05:11

it means you can do this (map inc (range))

bhauman22:05:33

which will go forever

bhauman22:05:02

but you can just take part of it

bhauman22:05:23

oh and don’t type that in the repl

bhauman22:05:16

@andrea_fleckenstein type this in the repl (take 3 (map #(do (prn "hey") (inc %)) (range)))

bhauman22:05:34

you will see that hey is only printed three times

bhauman22:05:47

your welcome 🙂

afleck22:05:22

that was not very intuitive, but at least now I won't make this mistake again..... hopefully

afleck22:05:18

@bhauman so it gets consumed in the repl because it is printed?

bhauman22:05:45

is there a good blog post on why lazyness is a super power in clojure?

Flancian22:05:44

ahoy! I started learning Clojure today; sorry if this is too basic a question, let me know 🙂 I ran into some surprising keyword behaviour and I haven't been able to explain it: scratch.core=> (:a :b) nil scratch.core=> (:a :b :c) :c scratch.core=> (:a :b :c :d) Execution error (IllegalArgumentException) at scratch.core/eval1783 (form-init1964860978058534137.clj:1). Wrong number of args passed to keyword: :a

hiredman22:05:44

user=> (get :b :a)
nil
user=> (get :b :a :c)
:c
user=> (get :b :a :c :d)
Execution error (ArityException) at user/eval5 (REPL:1).
Wrong number of args (4) passed to: clojure.core/get
user=>

hiredman22:05:53

it mirrors the get function

Flancian22:05:23

aaah -- that explains it, thanks @hiredman. (doc get) shows that the third parameter is what is returned in the not-found case, which makes sense.

Flancian22:05:42

is there any way I could have seen in the repl what was happening behind the scenes?

Flancian22:05:12

in my amateurishness, I ran (doc :a) expecting to see the "traits" of a keyword when used as a function.

Flancian22:05:18

but that didn't work.

didibus22:05:53

No, unfortunately for that you'd needed to refer to the docs

Flancian22:05:48

thanks all!

didibus22:05:45

Reading through https://clojure.org/reference/reader might feel a bit thick at first, but I still recommend it

Flancian22:05:59

on it, cheers for the tip 😄

didibus22:05:17

Even if you don't understand it all, later as you learn more, things will click and you'll know where to go looking back and re-read the reference and suddenly it'll make sense

👍 4
mister_m22:05:04

Could someone explain a little further what I am supposed to do with these installation instructions? https://github.com/cloverage/cloverage#installation It isn't clear to me where this dependency addition is supposed to happen. I don't have a .lein/profiles.clj. Is this supposed to be added directly to the :profiles section of my project.clj?

phronmophobic23:05:27

are you using lein?

phronmophobic23:05:09

adding the dependency directly to your :profiles section of your project.clj should work too

phronmophobic23:05:35

oh wait. adding it to the :plugins* section

phronmophobic23:05:08

.lein/profiles.clj is just if you want to be able to use cloverage from any clojure project without having to explicitly add it for every project

mister_m23:05:01

seems lein profiles plugins are deprecated, and the :user profile should be used instead

mister_m23:05:33

ex {:profiles {:user {:plugins [[blah]]}}}

noisesmith23:05:31

profiles.clj is one big profiles section right?

noisesmith23:05:05

but for cloverage, I would expect to add the plugin to a project, not my global config

mister_m23:05:42

right, that's what I'd prefer as well

noisesmith23:05:24

and there are a few good reasons to avoid global customization with lein

hiredman23:05:57

there are two members connected to this chat with the name "Nicole Kathrine", and at least of them seems to be spammer, if either of you is not a spammer the spammer my be trying to pretend to be you to avoid getting booted