This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-06-07
Channels
- # announcements (12)
- # aws (2)
- # beginners (233)
- # calva (68)
- # cider (23)
- # circleci (5)
- # clj-kondo (40)
- # cljsrn (4)
- # clojars (3)
- # clojure (200)
- # clojure-austin (1)
- # clojure-canada (1)
- # clojure-dev (16)
- # clojure-europe (1)
- # clojure-finland (1)
- # clojure-italy (4)
- # clojure-nl (16)
- # clojure-spec (3)
- # clojure-uk (102)
- # clojurescript (16)
- # cursive (14)
- # datomic (16)
- # figwheel-main (7)
- # graalvm (3)
- # hoplon (37)
- # jackdaw (23)
- # jobs-discuss (24)
- # joker (4)
- # kaocha (6)
- # keechma (64)
- # off-topic (66)
- # parinfer (1)
- # pedestal (7)
- # re-frame (7)
- # reagent (10)
- # reitit (45)
- # rewrite-clj (12)
- # shadow-cljs (1)
- # slack-help (8)
- # spacemacs (55)
- # sql (9)
- # tools-deps (9)
- # vim (7)
Agreed re: Midje. Definitely not recommended by quite a few folks @hi135
@hi135 FWIW, if you end up using spec for generative testing, expound can help format the results: https://github.com/bhb/expound#printing-results-for-check
I use midje like this (deftest foo (fact (+ 1 2) => 3))
and it's fine. #cursive interation and clj -A:test:test-runner
via cognitect-labs/test-runner
works. Also I have the power of contains/just
@souenzzo I've never found Midje's syntax readable, but it's good to know it can be used like that with deftest
. With expectations.clojure.test
that was my goal, so you can write (deftest foo (expect 3 (+ 1 2)))
-- and expect
lets you use specs, predicates, and you can "expect more" with destructuring etc.
if I run lein uberjar
with :aot :all
in :uberjar
profile, then all the macros should be expanded at compile time, right?
Typically yes. Aside from anything funky like calls to eval
.
hmm, I never considered that aspect of it - guess I'll just pick an arbitrary one-letter alias to use
you can just use :refer [deftest testing is are]
and get pretty far. I think i do that in addition to :as t
often I write ad-hoc rich comment blocks in the source file itself to test functions, and then graduate those to actual tests where it makes sense
But I still think of the test ns as belonging to the same "environment", so having to go and add prefixes to all the vars seemed unnecessary compared to just a :refer :all
I kind of like the approach of using :ss sut
(for system under test).
When just learning clojure, on my first clojure project I chose Midje because it seemed quite elegant to me at the time. I’m not sure I understand yet why some folks don’t like Midje. Is it that it tries to provide an easy way to write tests at the cost of complexity within itself? I don’t know. After dabbling in various open source projects for the last while, granted my sample size is small, I’ve not seen Midje used. Despite my original attraction to Midje, I don’t find myself suffering without it. Also, I think the author of Midje might have left the Clojure community?
Hoping over to clojure from being a JS dev, and still pretty new. (loving clojure btw) Is there some approximate equivalent to eslint/prettier that allows for configurable static analysis/style rules? I'm finding myself wanting some programmatic way to declare conventions within the repo, and eslint and its ecosystem used to fill that niche in my life oh so wonderfully.
@suni_masuno There is eastwood and cljfmt for instance . Also we have the clojure toolbox: https://www.clojure-toolbox.com/ which lists some more, but I am not sure how up to date it is.
Ohhhh man, that toolbox link looks awful pretty, if it turns out to be old and crusty I may just cry.
There are definitly up to date links inside, but I also found projects that are abandoned, so you just have to go through them.
I can survive that, thanks for the heads up. ^_^ Man, this is in fact a LOT of what I'm looking for. I take it from eastwood/cljfmt getting separate billing that they did to be a bit more commonly used than the others listed?
They were just the first that came to my mind and that I used myself. But, this is just me 😉
At the very least this thing is making reading the project.clj sooooo much easier!
the toolbox site takes PRs - if you find something out of date, please fix it!
I'm something like 10 in and so far all's well, but I'll be sure to contribute if I find anything!
I've also found a project or two in our project.clj that are in maintenance mode or otherwise look sketch and they aren't in the toolbox so... yeah I'm mildly impressed. ⛳ 👏
Oh yeah, these are fine here, I'm just impressed toolbox seems clear of them.
if you find missing stuff, you can add that too in a PR :)
@suni_masuno shameless plug, but there’s also my linter called clj-kondo: https://github.com/borkdude/clj-kondo/
it doesn’t have configurable conventions though, although you can turn off and on certain things
I have at the very least learned that configurable linting isn't anywhere near as big a part of the clojure community as it is the JS. Though honestly I don't think clojure needs it anywhere near as bad as JS. ^_^
And as a relative newb I'm finding all the rules people did think to write super useful
@suni_masuno you maybe want to look at “the” Clojure style guide: https://github.com/bbatsov/clojure-style-guide clj-kondo supports some of those
Read it, found it awesome and love it. ^_^
editing s-expressions is so much easier than curly-bracket/semi-colon languages when it comes to formatting 🙂
@michael.e.loughlin don’t even get me started about significant-whitespaced languages
@suni_masuno Another more opiniated one: https://github.com/metabase/metabase/wiki/Metabase-Clojure-Style-Guide
Ohhh, thanks! ^_^
Is there something wrong with me that I could read styleguides all day?
Someone runs my macro and passes in a namespaced symbol like so: (my-macro edn/read-string)
. How do I get the real namespace of this function I was passed in?
@roklenarcic what’s the the arg-list of your macro like? (defmacro my-macro [thing] ...)
?
If I go:
(defmacro my-macro [f] (namespace f))
(my-macro end/read-string) => "edn"
or:
(defmacro my-macro [f] `(namespace ~f))
then I get clojure.edn$read_string cannot be cast to clojure.lang.Named
I'd like "clojure.edn"
@roklenarcic I guess you can do something like this, but I’m still not sure what your use case is:
user=> (defmacro my-macro [sym] `(namespace (symbol (resolve '~sym))))
#'user/my-macro
user=> (my-macro contains?)
"clojure.core"
thanks I'll try that
my use case is that I want the macro to generate some keywords that match the ns of the first argument
note that that use of symbol is new in 1.10
so won't work on older versions
Ok, bigger question. I'm finding a lot of veeery long let statements (to my uninitiated eye) something like...
(defn
something
[ ~stuff~ ]
(let [a1 ( ~some stuff~)
a2 ( ~some stuff using a1~)
a3 ( ~some stuff using a1 and a2~)
a4 ( ~some stuff using a1 and a3~)
a5 ( ~some stuff using a2 and a4~) ~many of these are 2-5 lines long~
~more lines, usually around 10-15~
a17( ~some stuff using a15 and a16~)]
{[:stuffs ~hard coded data output shape useing a15-17~]}))
this feels like C++ crammed into clojure to me, but is this a pattern I just don't know?it depends, but I think you're right to be somewhat wary of such code
On my tests, I would like to mock a few functions that access the database. Any suggestions on a good mocking library or maybe I should just use "with-redefs-fn"?
When testing things with side effects like this, you tend to have three options:
1. directly mock, e.g. with with-redefs
2. build up and tear down a real db
3. devise a protocol for db access and provide e.g. a reified mock impl for tests
The choice is situational but I tend to use 2 and 3 more heavily.
To be honest, I usually go for 3 🙂. Since most people here tend to use 1 (on python code), I am trying to explore it and how it would feel in clojure code.
I did find a stack overflow related, but it seemed fuzzy on the answer. Is this a legit division in the community maybe? https://stackoverflow.com/questions/19492584/let-bloat-or-idiomatic-clojure
Personally I think the “bloated” let
style is actually a pretty good way to create “executable documentation,” assuming you give the intermediate values names that are informative and instructive.
if there are really a lot of intermediate meaningfully-named calculations, this may be fine
tasteful inlining can shorten that up
macros can remove a lot of duplication if you see repeated stuff
It feels so... iterative instead of declarative. Although I suppose no one is promising declarative as a goal of clojure
Also, I’m currently trying to work my way thru an issue where a key bit of code is one big long ->
macro, and I have to use the debugger because it’s a 3rd-party lib inside a 3rd party lib, and I’m basically stuck because there’s no way to inspect the intermediate values, so 😞
That said, while I prefer let
, blocks, I find that in my actual code, they’re usually not very long. Mostly 6 lines in the block, or less.
some code really is a series of computations that occur in order
It is iterative, but in Clojure it is still often purely functional (it isn't restricted to be, but often is)
well, sequential may be a better word than iterative there. Even then, lazy sequence processing can cause execution order to be different than it might first appear to be.
The code in that question is interoping with side effectful code. So it is going to be a bit more imperative. It has to be because of the imperative nature of the library it is calling. Let's can be a good tool for referencing values, especially if they are used multiple times in an expression. In general. I try to make my code so you can easily evaluate sub expressions in the repl. I find let's can often be annoying in that context.
I thought I saw something added to clojure a while back that allows you add a new dependency to an already running repl. Am I imagining this? Does anyone know what I'm thinking of here? I think it was something in clojure itself and more recent than pomegranate. Context: every once in a while I'd like to load something like a profiling library, but not often enough that I want to put it in my project or profiles.clj.
you're probably remembering the add-lib
stuff in deps.edn
which has not actually been integrated yet but is available for use on a branch via git dep
http://insideclojure.org/2018/05/04/add-lib/ (recent sha to use is e160f184f051f120014244679831a9bccb37c9de )
@dpsutton you might like https://github.com/Engelberg/better-cond although I've found it can divide opinions 🙂
you can put side-effecting :do
blocks in there
little too heavy and new-languagegy for this. just gonna cond->
into doto
forms this time
ah yeah, it's not exactly right for your use case anyway - sounds like you're banging on a object and want to do make some of the bangs conditional
@manutter51 In previous lives we had things like tap
in ramda for just that, executes whatever it's code is over args but returns args unmodified. Is there no clojure version of that?
does anyone know if I can create a zip file with ZipOutputStream without having files to zip?
I mean given a vector of strings for example, and a mapping to assign to each of them a filename in the zip file, can I write them out directly in the stream?
No authoritative knowledge from me, i.e. I have not done it myself before. The Java API page for ZipOutputStream strongly implies the answer is "yes", although you will have to make the appropriate method calls when you want to finish one file inside the resulting zip file, and start another. Also, it is based on OutputStream, which only lets you write bytes to it, not Java String directly, so you will need to pick an encoding for those strings (e.g. UTF-8).
If by your question you were hoping to avoid some minutes of experimenting with the Java API in case the answer is "no", then I haven't helped here 🙂
hehe no just asking if it's possible
I did experiment already but I could not find out to still pass an input-stream without a file
I'm using these two functions
(defmacro with-entry
[zip entry-name & body]
`(let [^ZipOutputStream zip# ~zip]
(.putNextEntry zip# (ZipEntry. ~entry-name))
~@body
(flush)
(.closeEntry zip#)))
(defn zip-files
"Zip all the given files into the desired output file"
[output-filename files]
(with-open [output (ZipOutputStream. (io/output-stream output-filename))]
(doseq [f files]
(with-open [input (io/input-stream f)]
(with-entry output f
(io/copy input output))))))
so I guess I just have to do the various magic bytes transofrmation
where it's doing the input and io/copy
This Java method getBytes is one way to convert a string to UTF-8, or any other encoding supported by your JVM: https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#getBytes-java.lang.String-
I am not sure the (flush)
call you have will do anything useful there, as I believe it flushes the *out*
OutputStream by default.
Maybe replace that with (.flush zip#)
? But perhaps the (.closeEntry zip#)
call flushes for you. I don't know.
If you have input-stream for each entry, you should not need to manually do any conversion from strings to bytes. The io/copy method should preserve the original byte sequences of the input files without any encoding/decoding stuff going on.
thanks @U0CMVHBL2 in the end I sorted it out by doing
(defn zip-content
"Zip all the given files into the desired output file"
[output-filename edns]
(println (format "zipping %d files into %s" (count edns) output-filename))
(with-open [output (ZipOutputStream. (io/output-stream output-filename))]
(doseq [[entry-name content] edns]
(with-entry output entry-name
(let [bs (.getBytes (str content))]
(.write output bs 0 (count bs)))))))
which seems to work welle
glad you got it working
@manutter51 I think judicious use of doto
should do the same thing, right?
Quick question: Is https://github.com/stuartsierra/component recommended as of 2019?
have used it extensively in 2019 in a bunch of projects, as happy as ever with it
I'd just make sure to use it via metadata-based protocol extension, to avoid Reloaded workflow
issues.
(Added in component 0.4.0)
There are some extensions paths, but you can start there
Is it possible to attach a Java annotation when creating a class with (proxy..)
?
Nice blog entry on not trying to do much with :prep-tasks
in lein
: https://grishaev.me/en/lein/
Hmm, there is some truth to this. But unfortunately the one case where I need to build my documentation using Antora needs to happen even for lein repl
, because it is served by an internal web server even when you are running locally from source.
I've noticed a slow but steady trend towards make
in the JS world as well. Gulp/Grunt seem to have entirely passed on, and even npm scripts are slowly losing favor
Imagine, a world where all the languages use the same build tool. ❤️
make is rather terrible in many ways though. It's not syntax aware. Gulp always seemed like a great solution to me.
What do you mean by syntax aware? (says the curious newb)
It can't perform any kind of dependency analysis automatically. Even though our code has those dependencies already.
is mach still being used in juxt? https://github.com/juxt/mach
Just to clarify, I like make for many reasons. But I don't think it's where we should aspire to finish.
How do I handle a comp ( -> and ->>) when my funcs go back and forth from data first to data last?
the other options listed here are OK, but ->> is usable inside -> for arbitrary alternation as well
in fact any of the arrow macros can be used inside ->
, that's why they all take a value as the first arg
That is downright clever
Note that you probably shouldn't do this regularly - see https://stuartsierra.com/2018/07/06/threading-with-style ("Dont mix -> and ->>")
90% as good... works for me
thanks!
Also, I must admit it's a kinda clever idea
Naw, but tone humor is really hard in text. ¯\(ツ)/¯
all's good
@suni_masuno I find Clojurians are typically smart, kind and generous. If tone is ever in question for you, you can assume friendly.
and just avoid threading altogether you mean?
Early convo ref https://clojurians.slack.com/archives/C03S1KBA2/p1559917190269200
You might be interested to macroexpand the as->
form to see what it actually does under the hood 🙂
oh gotcha, yeah i just jumped in at the end there
@suni_masuno when you need to thread through 17 expressions, it’s maybe good to chop it up into a few lets or functions
That seems pretty reasonable, I suppose finding that balance is part of the art.
Neat! I was invited to write a two-page spread for a new O’Reilly book titled “97 Things Every Java Programmer Should Know” that is also being serialized on Medium. Their process is a lot faster than it used to be—I wrote a draft yesterday, and it was just published: https://medium.com/97-things/rediscover-the-jvm-through-clojure-fa2ac5e29cbb
Hello all, I want to generate a clojure.java.jdbc
query infinite loop and leave it running without wait response. Is that possible?
probably subject to timeouts on your jdbc driver. I'm going to go out on a limb and say that it's probably not a good idea
@ghadi I have to do it for my unit test, that I´ll create blocking session to test if it exists
what do you mean by "infinite loop"? looping in clojure or in some PL/SQL or something?
you can put it in a background thread like a future, but without seeing the rest of the SQL this seems like there is a race condition in there
I can think of not clever ways, like generating a new pattern with named groups, each with a gensymd name, matching an empty string, and then make every pattern an alternation
1. it can handle context free languages which are a superset of regular languages 2. it has some syntax for specify terminals as regexes
(i mean regular expression in both the common java syntax and the parser-theory sense here)
there are some alternative java regex libraries as well, which might give you more options then the built in stuff
it drives me up the wall that I can't just combine Patterns with some kind of or combinator
my second guess was the "make a new pattern with alternations and empty named groups in front"
instaparse's regexp
is a real regular expression, not the full-fledged pcre-style thing with backrefs, right?
(I guess I don't realllllly care, but I happen to know all of these regular expressions are actually regular)
https://github.com/Engelberg/instaparse/blob/master/src/instaparse/combinators_source.cljc#L88-L93
that's somewhat unfortunate because I already do sequential matches, and presumably instaparse can't do any better (computationally, I mean -- maybe syntactically, sure)
that's correct, instaparse will defer to java regexes re: performance of each individual parse
the main goal of the regex terminal is to attempt to plug the syntactic power of regexes into the high-level parse / backtracking engine of instaparse
it isn't a super clean fit since instaparse assumes a 1:1 mapping from start-positions in the string to regex results, where it could actually be 1:many
I mean, it doesn't matter tremendously because since Matcher only supports .group(String groupName)
you still have to enumerate all possible groups to know which one matched exactly, meaning I'm not going to be happy with how this looks regardless
if instaparse had a "build your own combinator" support would that help at all?
I mean I've never used instaparse's combinators but I have a hard time believing you wouldn't have all the stuff you needed for regular languages, so yeah
I would asusme the way to implement this is to parse the regex Java(TM) pattern string with instaparse, compile the parse to an instaparse parser with combinators, then have {:A firstpattern :B secondpattern ...}
Any "pure" regex (i.e. one from classic automata theory that represents a regular language, without some of the lookahead/lookbehind stuff that Perl and some other regex libraries added on top of that) can be combined with any number of other regexes to create a deterministic finite automata that recognizes the intersection, union, and/or complement of those languages, too. It can make the number of states in a deterministic finite automata get pretty large.