Fork me on GitHub
#beginners
<
2019-01-10
>
mathpunk00:01:04

I'm seeing if I can turn my project.clj into a deps.edn. Can't figure out using a github repo. E.g., :deps {com.github.cognitect/transcriptor {:git/url "" :sha "05e9eb093b21d9a3458e0d946ad9dab76ae1e1c8"}...} gives "Manifest type detected"

mathpunk00:01:31

I do succeed, however, if I use com.cognitect/transcriptor {:mvn/version "0.1.5"}

mathpunk00:01:40

(that last being, a verification that the library is includeable)

hiredman00:01:00

you need the url to the git repo

hiredman00:01:10

not the github webpage for the repo

mathpunk00:01:31

yes of course

mathpunk00:01:29

reasonable idea! but, no

mathpunk00:01:20

:thinking_face:

mathpunk00:01:15

status code is a 301

mathpunk00:01:09

also the guide suggests a form like {:git/url "" :sha "04d2744549214b5cba04002b6875bdf59f9d88b6"}}} which..... seems like what I used

noisesmith00:01:00

aren't the two forms [email protected]:foo/bar.git and the https form?

noisesmith00:01:56

so I'd try [email protected]:cognitect-labs/transcriptor.git

hiredman00:01:57

no, if yo go to repo and click the clone button the url it gives you is the https url with .git

eval202000:01:01

the root of the project does not contain a deps.edn

eval202000:01:26

I tried successfully with the following deps.edn:

{:deps {clt {:git/url "" :sha "05e9eb093b21d9a3458e0d946ad9dab76ae1e1c8" :deps/root "examples"}}}

seancorfield00:01:31

The examples subproject relies on the non-git version of transcriptor, however...

eval202000:01:42

indeed, no benefit it seems to use a sha…

seancorfield00:01:45

You can rely on a version of the examples project, but that doesn't get you transcriptor itself via git 🙂

mathpunk01:01:11

ah, can :git/url not load projects based on a project.clj?

mathpunk01:01:57

it appears not, ok

seancorfield02:01:15

tools.deps does not understand project.clj -- only pom.xml and deps.edn (I think that's all)

hiredman00:01:42

yeah, that is the problem, it isn't a deps.edn project

vincentdm00:01:56

Hi guys! Question: I have a spec defined like this:

(s/def ::person (s/keys :req [::foo ::bar ::baz]))
In another namespace, I need a similar spec like ::person, but with all keys as optional. Is there a way to copy the ::person spec and change the req keys into opt keys?

seancorfield00:01:47

@vincentdm Not any easy way, no. This is a problem that Rich talked about at Conj and a future version of clojure.spec will address this.

vincentdm00:01:23

Rings a bell! Okay, then I won't waste time in this avenue. Thanks!

seancorfield00:01:25

The problem is that s/keys complects shape and requiredness.

✔️ 5
Chris Kellendonk00:01:51

Hi all, new here. Not sure what the correct etiquette for asking new questions is but...Is there a built in function similar to clojure.core/time but allows for prepending a string to the output of elapsed time output. I find when using lots of time calls it can get confusing where they are from. I know it's simple enough to write this myself using do but just curious if there is already something built in?

noisesmith00:01:42

@chriskellendonk probably easiest is to use with-out-str and then modify the string you capture

Chris Kellendonk00:01:48

Oh nice, thanks I didn't know that existed. I'll check it out looks pretty close to what I need

noisesmith00:01:13

user=> (str "foo: " (subs (with-out-str (time (+ 1 1))) 1))
"foo: Elapsed time: 0.010721 msecs\"\n"

noisesmith00:01:23

it's sloppy still, but it's a start

Chris Kellendonk00:01:55

Yeah I will probably just write my own helper to wrap this

seancorfield00:01:58

And how do you get the original value in that case?

Chris Kellendonk00:01:41

ah good point, this does not pass the output through

seancorfield00:01:45

Where did 2 go? 🙂

user=> (time (+ 1 1))
"Elapsed time: 0.038226 msecs"
2
user=> (with-out-str (time (+ 1 1)))
"\"Elapsed time: 0.009613 msecs\"\n"

noisesmith00:01:13

yeah, you could use a promise or whatever to capture the return value

noisesmith00:01:17

but that seems ugly

Chris Kellendonk00:01:20

I was using

(time (do (print "Timed =>") (+ 1 1)))

Chris Kellendonk00:01:40

which works, but was hoping this may be built in. Sounds like it's not though. Thanks for the help 👍

seancorfield00:01:10

Here's what we use:

(defmacro with-time
  "Evaluates expr and returns a map of the :value and the :time (in ms)."
  [key & expr]
  (let [value (if expr key :value)
        expr (if expr (first expr) key)]
    `(let [start# (System/nanoTime)
           ret# ~expr]
       {:time (/ (double (- (System/nanoTime) start#)) 1000000.0)
        ~value ret#})))

👍 5
noisesmith00:01:21

(ins)user=> (defn timed [f] (let [res (promise) timing (with-out-str (deliver res (time (f))))] {:result @res :time timing}))
#'user/timed
(cmd)user=> (timed #(+ 1 1))
{:result 2, :time "\"Elapsed time: 0.029535 msecs\"\n"}

seancorfield00:01:21

Return a hash map with the time and the value.

noisesmith00:01:48

yeah, that macros probably the smarter bet

seancorfield00:01:11

The docstring was not written with the public in mind 🙂

Chris Kellendonk00:01:19

I still want the value to be passed through as normal with time. I just want to add my own custom string so it reads "My string => Elapsed time: 0.029535 msec"

noisesmith00:01:42

that's straightforward to do without a macro, in that case

seancorfield00:01:46

(with-time expr) produces {:time .. :value ..} whereas (with-time :x expr) produces {:time .. :x ..}

Chris Kellendonk00:01:10

I don't know the macro syntax but something like

(defmacro time-with-str
  "Evaluates expr and prints the time it took.  Returns the value of
 expr."
  {:added "1.0"}
  [my-str expr]
  `(let [start# (. System (nanoTime))
         ret# ~expr]
     (prn (str my-str  " Elapsed time: " (/ (double (- (. System (nanoTime)) start#)) 1000000.0) " msecs"))
     ret#))

Chris Kellendonk00:01:05

This still returns the normal output but lets me use a custom string to mark this specific call

noisesmith00:01:13

(defmacro time-str [prefix & body] `(let [start# (System/nanoTime) ret# (do ~@body) time# (- (System/nanoTime) start#)] (println (str ~prefix time#)) ret#))

noisesmith00:01:21

about the same thing

noisesmith00:01:11

using prn in this context seems odd, as it just forces awkward quoting of the string part of the output

noisesmith00:01:50

(. System (nanoTime)) might make sense in the context where clojure.core/time is defined, or might have been the right code when it was implemented, but it's not how we'd normally do interop

Chris Kellendonk00:01:00

That’s good to know. And thanks for the implementation

noisesmith00:01:03

oh now i see that clojure.core/time was using prn - I guess that' s to make it clearer in the repl that what you are seeing is separate from the return value?

Vincent Cantin06:01:54

Which predicate would return true on a vector, a list, a set or a sorted-set, and false on a map?

Lennart Buit06:01:44

(sequential? ...) maybe

Lennart Buit06:01:56

eh bah, not on set

Lennart Buit06:01:21

I guess your best bet would be to assert that it is seq?, but not map?, I don’t think that all non-mapping collections have a common ancestor. Edit: or is coll? and not associative? is maybe better.

Vincent Cantin06:01:50

Okay, thank you.

Lennart Buit06:01:33

Theres also a stack btw, as a collection, it doesn’t have a simple syntax for creating, but it can be useful at times

Lennart Buit06:01:48

(prove me wrong tho!)

jaihindhreddy-duplicate09:01:06

Are the semantics of #inst defined at the level of EDN or Clojure syntax?

jaihindhreddy-duplicate09:01:46

^ Please ignore. #inst and #uuid are part of EDN.

jaihindhreddy-duplicate11:01:22

Are there plans to add more tags in EDN? (Stuff like IP addresses and URLs) I did check out this discussion on google groups about #inst and tagged literals in general:

Alex Miller (Clojure team)11:01:05

no plans to add those to core atm

👍 5
Alex Miller (Clojure team)11:01:23

you can of course add any tagged literals you like

Ian Fernandez14:01:18

How I do a validation on a map with prismatic schema that returns the data if the data is correct or empty string if the data is incorrect?

Ian Fernandez14:01:25

I ask on schema's channel?

jaihindhreddy-duplicate15:01:52

#schema is probably more appropriate.

boogie66615:01:52

can anybody help me with something? I'm trying to read a clojure file and analyze the forms, but it looks like autoresolved keywords can't be read 😞 I'm not sure what to do...

Alex Miller (Clojure team)15:01:30

how are you reading it?

Alex Miller (Clojure team)15:01:31

the reader has a pluggable system for resolution so it is possible to plug in your own handler there to give it the “namespace context” if needed

boogie66615:01:10

i figurred it out 🙂 thx

boogie66615:01:56

had to bind the reader-resolver to some NoOp impl of a LispReader$Resolver

boogie66615:01:44

i guess that's what you mean alex

mathpunk19:01:45

I keep getting this at various times:

mathpunk19:01:48

SLF4J: Failed to load class "org.slf4j.impl.staticloggerbinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See  for further details.

mathpunk19:01:04

This isn't anything I'm depending on directly... presumably something else I'm depending on is

mathpunk19:01:37

not sure if I should just ignore it or address it in my project.clj somehow, or what

mathpunk19:01:46

it's red, that's never good

Alex Miller (Clojure team)19:01:57

SLF4J is a logging API with pluggable impls

Alex Miller (Clojure team)19:01:02

many Java libraries use it

mathpunk19:01:24

I'm using a JGit wrapper, that's my first suspicion

Alex Miller (Clojure team)19:01:40

what it means is that one of those libs wrote a log statement, and no log impl was found, so it’s using the default (which does nothing)

mathpunk19:01:59

and since I'm not logging anything, /shrug

Alex Miller (Clojure team)19:01:24

you can add an additional dependency on one of the explicit slf4j impls and then use that to configure the logging

Alex Miller (Clojure team)19:01:43

if you want the warning to go away

eval-on-point19:01:10

I get similar errors when I boot up CIDER on an empty lein project

mathpunk19:01:50

I see that https://github.com/clojure/tools.logging exists.... if I include it, what else would I need to do?

Alex Miller (Clojure team)19:01:22

well, that will only deepen your problems :) tools.logging is also a pluggable logging api.

Alex Miller (Clojure team)19:01:33

you can plug slf4j in underneath it though :)

Alex Miller (Clojure team)19:01:25

You can include the dep org.slf4j/slf4j-nop to explicitly tell it to not do anything

eval-on-point19:01:08

Thanks, Alex. I'll try that tonight when I'm at home

🍻 5
mathpunk20:01:19

that's.... not something I would have thought of 🙂 thanks Alex

mathpunk20:01:39

(I am tickled by having the option of choosing a beta version of no-op)

Alex Miller (Clojure team)20:01:50

choose your favorite vintage :)

😂 5
Lennart Buit20:01:00

this is one of those great tragedies of software right, there where once too many logging frameworks. Now there are too many logging framework frameworks

Lennart Buit20:01:41

yeah but then one meta level higher

mseddon20:01:47

🙂 true that.

Alex Miller (Clojure team)20:01:45

everything about Java logging should be set on fire

Alex Miller (Clojure team)20:01:19

but how would I log that I did it

5
Lennart Buit20:01:29

this is a problem that seems to plague the java ecosystem most

Lennart Buit20:01:39

how did other platforms deal with it

andy.fingerhut20:01:21

Python has a built-in logging library that seem to be well-known enough and good enough that most people simply use it. I wouldn't be surprised if there are a few various implementations from years ago that are effectively "dead" now because of that.

jaide21:01:24

Oops I totally missed the “built-in” part 😔

noisesmith21:01:03

also logging is something that is cross-cutting - needed at many levels, and its users expect to apply a single solution across libraries

noisesmith21:01:05

so if something usable isn't in the default setup built in, you end up with lots of hacky attempts at modularity and compatibility and "dependency injection" that make the whole thing harder to understand or use properly

Lennart Buit21:01:21

right, I must admit that I always use timbre in clojure. And most libs of my comp also use timbre. So basically, if something doesn’t its part of the problem

seancorfield21:01:49

The other nice thing about Timbre -- and some of its satellite libraries -- is that you can "hijack" pretty much every Java logging library and force them all through Timbre, giving you centralized control.

Lennart Buit21:01:35

yeah, was looking into that. Can you do it the other way around tho, or is it unwise to depend on Timbre if you publish a lib

seancorfield21:01:45

Well... Timbre pulls in a bunch of other dependencies from the same author... and that has often bothered me enough to want to switch to something else...

seancorfield21:01:07

...but whenever I've tried, the pain of logging usually makes me go back to Timbre 🙂

Lennart Buit21:01:34

So I added that bridge thing, slf4j-timbre, and now some java dep decided to DEBUG spam, do perhaps know how to tell timbre to drop everything below INFO from external deps?

seancorfield21:01:10

timbre/set-level! -- needs to be called before those other libraries get up and running. I tend to have that in my main namespace as a top-level call.

Lennart Buit21:01:41

yeah, but that also silences my own debugs, no?

seancorfield21:01:13

You can also blacklist packages/namespaces -- see https://github.com/ptaoussanis/timbre#configuration

seancorfield21:01:40

For example (from our code at work):

(taoensso.timbre/merge-config! {:ns-blacklist ["com.eclipse.*"
                                                 "org.eclipse.*"
                                                 "org.apache.http.*"
                                                 "org.redisson.*"
                                                 "com.mchange.*"]
                                  :level :debug})

Lennart Buit21:01:42

Yeah, but thats a blanket ban, not level based. Well, I think I’ll learn to live with not having debug

Lennart Buit21:01:51

OH, you can pass a level

seancorfield21:01:13

No, that sets the level to debug but blacklists those packages.

seancorfield21:01:23

By default, we set the level to info.

seancorfield21:01:34

We have

(timbre/set-level! :info)
as a top-level form, immediately after the ns form in our main namespace -- to suppress any/all debug/trace stuff at startup, then we blacklist stuff we're not interested and go back to debug level if needed in dev/test.

seancorfield21:01:58

I don't believe you can set different levels for different packages/namespaces...?

Lennart Buit21:01:06

Right, its the kafka library thats very spammy, but luckily for me in a particular package only.

Lennart Buit21:01:16

So I’ll just blacklist that

Lennart Buit22:01:21

So, it turns out that you can write a custom middleware function to achieve such a feat

seancorfield21:01:52

I think it's reasonable for a library to depend on tools.logging and then users can do what they want with it -- including using Timbre to control everything.

Lennart Buit21:01:03

Right, that makes sense

Lennart Buit21:01:25

… added slf4j-timbre to my project, now I get spammed with debug info of one of its libs

michaels21:01:00

I’m back on the clojure wagon for a bit. Just got my vs-code set up with calva, and worked through the 4th chapter of Brave and True. It uses Lein - and I still don’t fully understand what the bounds of that are. When I start lein repl, it’s giving me a `Warning: implicit middleware found: cider-nrepl.plugin/middleware Please declare all middleware in :middleware as implicit loading is deprecated.` - is that something I should resolve, or ignore for now?

noisesmith21:01:19

sounds like something the CIDER devs need to fix - or may have fixed in a newer version

dpsutton21:01:53

@wmichaelshirk do you have an old project.clj or something with cider-nrepl in it? If you are just starting lein repl there should not be any CIDER deps in it at all.

michaels21:01:51

I had an ancient profiles.clj in my home directory when I started yesterday. I didn’t know what it did, but it was causing problems. I just deleted everything in it. That got my lein repl working - though with a warning that my profiles.clj was invalid. I was still having trouble getting running with calva (clojure extention for vs code), and it was suggested to me to copy this in: `

michaels21:01:58

{:user {:plugins [[cider/cider-nrepl "0.20.0-SNAPSHOT"]
                  #_[lein-figwheel "0.5.19-SNAPSHOT"]]
        :dependencies [#_[cider/piggieback "0.3.10"]
                       [nrepl "0.5.3"]
                       #_[figwheel-sidecar "0.5.19-SNAPSHOT"]]
        :repl-options {:nrepl-middleware [#_cider.piggieback/wrap-cljs-repl]}}}

michaels21:01:07

That worked to get everything working.

dpsutton21:01:18

ok. and what is your version of lein?

dpsutton21:01:01

ok that's the most recent one

dpsutton21:01:19

is it still saying your profiles.clj is invalid?

michaels21:01:24

No - it’s accepting that fine now.

dpsutton21:01:58

ah so is your issue resolved?

michaels21:01:23

in terms of everything appearing to work - yes. 😉 Just wondering if this lein warning is something to be concerned about

dpsutton21:01:35

one last thing is that there's been a migration from tools.nrepl to nrepl/nrepl. and they clash. perhaps some of your deps have a dep on the older tools.nrepl

dpsutton21:01:47

you can run lein deps :tree to see what deps are required and why

noisesmith21:01:55

or lein deps :plugins-tree if you need to check plugin deps

michaels21:01:58

grepping nrepl, I get

[cider/cider-nrepl "0.20.0-20190108.170816-9"]
 [nrepl "0.5.3"]
   [nrepl/bencode "1.0.0"]

noisesmith21:01:00

as these aren't project deps

michaels21:01:44

same thing, but with an :exclusions [[org.clojure/clojure]] on [nrepl

dpsutton21:01:09

sorry not project.clj, i mean profiles.clj

noisesmith21:01:58

the version of CIDER that Calva would recommend is likely older than the one that makes the latest lein happy

JoshLemer22:01:55

Are transducers commonly used in clojure?

Vincent Cantin03:01:15

@joshlemer In case you are learning about them, I may suggest you to take a look at this transducer blog post serie and its exercises. https://vincent.404.taipei/clojure/build-your-own-transducer-part1/ https://github.com/green-coder/transducer-exercises

Vincent Cantin03:01:47

I hope it helps.

seancorfield22:01:00

@josh_tackett We've used clj-webdriver for years but it is no longer maintained. I've been looking at switching to Etaoin but haven't had the time to investigate it fully yet. I had not heard of that other one.

seancorfield22:01:42

@joshlemer Define "commonly". I think they are being used more and more these days but I'm not sure I'd say they were "common" yet.

seancorfield22:01:57

It can take a while before new features are really internalized by developers at large and become "the norm". We're only recently seeing "common" usage of the Socket REPL that was introduced in Clojure 1.8, for example, and people are still asking lots of questions about clojure.spec introduced in 1.9.

seancorfield22:01:58

I think transducers are great -- but they can take a bit of getting your head around -- and a lot of material out there about Clojure was written before they were added so folks aren't as widely exposed to them yet as I think they will/should be.

josh_tackett22:01:33

@seancorfield I'm in the exact same position 🙂 Here are some notes I made about switching. Hope they are helpful: clj-webdriver to Etaoin - to -> go - current-url -> get-url - wait -> wait-visible - input -> fill-human - element & click -> query & click-el

seancorfield22:01:17

We've started using HtmlUnit for some newer applications -- and nearly everything we have clj-webdriver tests for is legacy and will be retired (this year) -- so we must stick with HtmlUnit going forward rather than convert the legacy tests and/or take on a new Selenium library.

Chase23:01:18

hello, I think I'm confused on how to bring in libraries. I want to use exponential math so am trying to bring in the math.numeric-tower library like so:

(ns armstrong-numbers
  (:require [clojure.math.numeric-tower :as math]))
but I keep getting an error.

Chase23:01:36

I get the same error when I change the dash to an underscore.

Chase23:01:59

Error:

Caused by java.io.FileNotFoundException
   Could not locate clojure/math/numeric_tower__init.class,
   clojure/math/numeric_tower.clj or clojure/math/numeric_tower.cljc
   on classpath. Please check that namespaces with dashes use
   underscores in the Clojure file name.

noisesmith23:01:20

what are you doing to add that library to your project?

noisesmith23:01:28

it doesn't come with clojure

Chase23:01:35

hmmm. I was just trying to follow along with this: http://clojure-doc.org/articles/cookbooks/math.html

Chase23:01:48

Do I need to put it in my project.clj dependencies?

noisesmith23:01:04

that would be the standard way to do it if you are using lein, yes

Chase23:01:59

what is the idiomatic way to do exponeniation (ex 3 ^ 3) in clojure?

noisesmith23:01:22

user=> (Math/pow 3 3)
27.0

noisesmith23:01:34

that's what comes with the vm at least

Chase23:01:59

ahhh, ok, I think I had found that first. Math/pow is a java thing right?

noisesmith23:01:01

I think numeric tower tries harder to use precise types

pberganza23:01:53

So, as I understand so far, clojure.spec and functions pre- and post-conditions server similar purposes (typechecking at runtime). Is clojure.spec supposed to replace the latter? Or is there something I'm not understanding about their usage?

noisesmith23:01:13

if you review, that has the standard things like pow, abs, floor, ceil, cos, sin, sqrt etc. etc.

Chase23:01:48

so what do I put in dependencies for the numeric tower? [clojure/math/numeric_tower "0.0.5"]?

noisesmith23:01:34

@pberganza10 just definign a spec isn't enough to make it get checked, you can use spec checks in a :pre or :post, and you can explicitly turn on checking for a specced function

pberganza23:01:18

Ahhh. Think I got it. But what do you mean by you can explicitly turn on checking for a specced function?

noisesmith23:01:22

https://clojure.org/guides/spec#_instrumentation_and_testing if you don't turn on instrumentation, the specs you declare aren't checked

noisesmith23:01:33

(unless you manually check things inline)

pberganza23:01:27

Got it! Thanks a lot ❤️

noisesmith23:01:41

(at work, I've dealt with code that was specced incorrectly, and there was no indication that it was because no code path actually ever checked args)

seancorfield23:01:47

@pberganza10 instrumentation and checking are good for development, but spec can also be used explicitly in your code for production use via s/conform and s/valid?

seancorfield23:01:09

We use spec very heavily at work, both in our development/test work and also in our production code for validation of data structures (such as API inputs).

pberganza23:01:57

Ok so spec has a much general use-case than I thought. I guess I could compare it to schema validation on other languages (e.g. Marshmallow in Python)?. So pre- and post-conditions are exclusively used for feedback during development,?

noisesmith23:01:16

@chase-lambert I think the article you linked had a link to the numeric tower project, that will tell you the right way

noisesmith23:01:38

it's probably more like [org.clojure/math.numeric-tower "..."]

Chase23:01:56

yup, too obvious. sorry about that

Chase23:01:11

there was a link right to the github at the top

noisesmith23:01:27

yeah, and the github shows the dep vector to use