This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-09-06
Channels
- # announcements (3)
- # beginners (83)
- # calva (11)
- # cider (24)
- # cljdoc (2)
- # cljs-dev (1)
- # clojure (216)
- # clojure-berlin (1)
- # clojure-dev (18)
- # clojure-europe (8)
- # clojure-italy (5)
- # clojure-losangeles (2)
- # clojure-nl (4)
- # clojure-spec (34)
- # clojure-uk (75)
- # clojuredesign-podcast (12)
- # clojurescript (33)
- # clojutre (13)
- # community-development (1)
- # core-async (38)
- # cursive (19)
- # datomic (28)
- # duct (3)
- # emacs (1)
- # events (5)
- # figwheel-main (3)
- # fulcro (93)
- # kaocha (20)
- # lambdaisland (2)
- # off-topic (40)
- # pathom (17)
- # pedestal (8)
- # quil (1)
- # re-frame (14)
- # reitit (19)
- # shadow-cljs (34)
- # sql (8)
- # tools-deps (6)
- # vim (1)
- # xtdb (8)
- # yada (18)
@ag here's an example
(! 694)-> lein new compojure ag/slurp-example
Thu Sep 05 18:28:51
(sean)-(jobs:0)-(~/clojure)
(! 695)-> cd slurp-example/
Thu Sep 05 18:28:54
(sean)-(jobs:0)-(~/clojure/slurp-example)
(! 696)-> cat project.clj
(defproject ag/slurp-example "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url ""
:min-lein-version "2.0.0"
:dependencies [[org.clojure/clojure "1.10.0"]
[compojure "1.6.1"]
[ring/ring-defaults "0.3.2"]]
:plugins [[lein-ring "0.12.5"]]
:ring {:handler ag.slurp-example.handler/app}
:profiles
{:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
[ring/ring-mock "0.3.2"]]}})
Thu Sep 05 18:28:56
(sean)-(jobs:0)-(~/clojure/slurp-example)
(! 697)-> lein repl
...
user=> (take 100 (slurp ( "compojure/core.clj")))
(\( \n \s \space \c \o \m \p \o \j \u \r \e \. \c \o \r \e \newline \space \space \" \A \space \D \S \L \space \f \o \r \space \b \u \i \l \d \i \n \g \space \R \i \n \g \space \h \a \n \d \l \e \r \s \space \f \r \o \m \space \s \m \a \l \l \e \r \space \r \o \u \t \e \s \. \newline \newline \space \space \C \o \m \p \o \j \u \r \e \space \r \o \u \t \e \s \space \a \r \e \space)
user=>
It's really just one line of code -- the rest was all setup 🙂 But I find sharing a REPL session to be a good way to illustrate solutions.
All the files in all the libraries that your project depends on are available directly from the classpath at runtime. You just have to know the relative path of the file you want.
hey all - I asked before awhile ago, but don't think I saw an answer. How would I use spec fdef to define this function of 0 arity, as well as instrument the return value for correctness? (defn get-num [] 42)
@m131 instrument
does not check :ret
or :fn
-- only :args
: it checks that calls made to the function are correct. check
is what you use to ensure that the behavior of the function is correct. Here's an example based on your get-num
:
user=> (require '[clojure.spec.alpha :as s] '[clojure.spec.test.alpha :as st])
nil
user=> (defn get-num [] 42)
#'user/get-num
user=> (s/fdef get-num :args (s/cat) ; empty argument list
:ret int? ; returns an int
:fn #(= 42 (:ret %)) ; describes properties of the
; function in terms of :args
; and :ret
)
user/get-num
user=> (st/instrument `get-num)
[user/get-num]
user=> (get-num :foo)
Execution error - invalid arguments to user/get-num at (REPL:1).
(:foo) - failed: Extra input
user=> (get-num)
42
user=> (st/check `get-num)
({:spec #object[clojure.spec.alpha$fspec_impl$reify__2524 0xaa549e5 "clojure.spec.alpha$fspec_impl$reify__2524@aa549e5"], :clojure.spec.test.check/ret {:result true, :pass? true, :num-tests 1000, :time-elapsed-ms 59, :seed 1567744480324}, :sym user/get-num})
user=>
Then if we change get-num
to return a wrong value:
user=> (defn get-num [] 13)
#'user/get-num
user=> (st/instrument `get-num) ; we need to instrument the new definition to get call checking!
[user/get-num]
user=> (get-num :foo)
Execution error - invalid arguments to user/get-num at (REPL:1).
(:foo) - failed: Extra input
user=> (st/check `get-num)
({:spec #object[clojure.spec.alpha$fspec_impl$reify__2524 0xaa549e5 "clojure.spec.alpha$fspec_impl$reify__2524@aa549e5"], :clojure.spec.test.check/ret {:shrunk {:total-nodes-visited 0, :depth 0, :pass? false, :result #error {
:cause "Specification-based check failed"
:data {:clojure.spec.alpha/problems [{:path [:fn], :pred (clojure.core/fn [%] (clojure.core/= 42 (:ret %))), :val {:args {}, :ret 13}, :via [], :in []}], :clojure.spec.alpha/spec #object[clojure.spec.alpha$spec_impl$reify__2059 0x6eeade6c "clojure.spec.alpha$spec_impl$reify__2059@6eeade6c"], :clojure.spec.alpha/value {:args {}, :ret 13}, :clojure.spec.test.alpha/args (), :clojure.spec.test.alpha/val {:args {}, :ret 13}, :clojure.spec.alpha/failure :check-failed}
(long stack trace omitted)thanks - is the :ret
keyword actually used in anyway? or just documentation? I assume check is just doing something like the generative testing?
check
verifies that the result of calling get-num
conforms to whatever :ret
specifies -- if :ret
is present -- and it also checks whatever :fn
specifies (again, if present), passing in a hash map with {:args {}, :ret 13}
in this case.
Both :ret
and :fn
are optional. Sometimes you'll want both, sometimes you'll just want one of them.
The :args
hash map has keys named for each argument.
So, what am I missing here? No output is given, just a nil eval result to both stest calls):
(s/fdef get-num :args (s/cat) :ret int? :fn #(int? (:ret %)))
(defn get-num [] "dog")
(stest/instrument `get-num)
(stest/check `get-num)
And, yes, check
is all about generative testing. It uses the :args
spec to generative conforming argument data, calls the function, then checks the result (using :ret
and/or :fn
).
(! 703)-> clj -A:test
Clojure 1.10.1
user=> (require '[clojure.spec.alpha :as s] '[clojure.spec.test.alpha :as stest])
nil
user=> (s/fdef get-num :args (s/cat) :ret int? :fn #(int? (:ret %)))
user/get-num
user=> (defn get-num [] "dog")
#'user/get-num
user=> (stest/instrument `get-num)
[user/get-num]
user=> (stest/check `get-num)
({:spec #object[clojure.spec.alpha$fspec_impl$reify__2524 0xa4ca3f6 "clojure.spec.alpha$fspec_impl$reify__2524@a4ca3f6"], :clojure.spec.test.check/ret {:shrunk {:total-nodes-visited 0, :depth 0, :pass? false, :result #error {
:cause "Specification-based check failed"
:data {:clojure.spec.alpha/problems [{:path [:ret], :pred clojure.core/int?, :val "dog", :via [], :in []}], :clojure.spec.alpha/spec #object[clojure.spec.alpha$spec_impl$reify__2059 0x698122b2 "clojure.spec.alpha$spec_impl$reify__2059@698122b2"], :clojure.spec.alpha/value "dog", :clojure.spec.test.alpha/args (), :clojure.spec.test.alpha/val "dog", :clojure.spec.alpha/failure :check-failed}
I suspect you had a definition of get-num
in your REPL already and the s/fdef
referred to that, but then you redefined get-num
?probably - for repl based workflow, what would I have to do to avoid that pitfall? Reset the repl session ?
(BTW, you need test.check
as a dependency for stest/check
to work -- that's what my -A:test
alias adds)
You could eval the s/fdef
after the defn
of get-num
, just to be sure.
oh yup, this is missing test.check in this particular toy-project. Is there a reason it isn't just included? Without it, can stest/check ever do anything useful/
(although, FWIW, when I ran those in the REPL with an existing get-num
definition, it still worked for me)
clojure.spec.alpha
doesn't need it for anything. Only clojure.spec.test.alpha
needs it -- so it is lazy-loaded in there.
It's expected that folks would use clojure.spec.alpha
in production code, but clojure.spec.test.alpha
only in dev/test code.
(and you don't want test.check
included in your production code in general)
Without test.check
, I get this:
(! 706)-> clj
Clojure 1.10.1
user=> (require '[clojure.spec.alpha :as s] '[clojure.spec.test.alpha :as stest])
nil
user=> (s/fdef get-num :args (s/cat) :ret int? :fn #(int? (:ret %)))
user/get-num
user=> (defn get-num [] "dog")
#'user/get-num
user=> (stest/instrument `get-num)
[user/get-num]
user=> (stest/check `get-num)
({:spec #object[clojure.spec.alpha$fspec_impl$reify__2524 0x774698ab "clojure.spec.alpha$fspec_impl$reify__2524@774698ab"], :clojure.spec.test.check/ret {:result #error {
:cause "Could not locate clojure/test/check/generators__init.class, clojure/test/check/generators.clj or clojure/test/check/generators.cljc on classpath."
same - thanks - I was able to reproduce your results with clj directly and not attempting in the lein project that had other dependencies
Cool. I always try to repro stuff with the smallest set of deps possible, and always with clj
, in order to avoid any weirdness that comes from Leiningen plugins or other project artifacts.
Hi Clojurians, if any of you are stuck in SQL land for some applications but still want pull-like syntax on your entities, here's a library for that: https://exoscale.github.io/seql/
cool! how does this compare to https://github.com/walkable-server/walkable?
seql is much more narrow than walkable in size, scope, and intent: - it can target a single database instance at a time - it can only target SQL databases - it is a library, not a full fledged server (though we have the server bits internally which will be open soon)
the library part allows us to use that in several places throughout the codebase in places where we don't necessarily want to have RPC overhead
@U06V097TP It looks very nice. Have you considered using next.jdbc
instead of clojure.java.jdbc
? (happy to follow up in #sql rather than this thread)
@U04V70XH6 yes, didn't know about #sql, will join
hi @U06V097TP, Walkable's author here. It's great to see EQL being adopted among Clojure community. What about introducing it in #announcements?
about the last two points you made about the differences between walkable and seql, walkable targets SQL db only, too and it's also just a library - you have to put it behind Ring/Pedestal if you want a real server - or you can use it in a react native (cljs) project to read from a local sqlite file so no server involved there
walkable doesn't support mutations at all, however
You've called string on a LazySeq so you now have a string of value equal to clojure.lang.LazySeq...
, maybe you want to do (apply str (interpose ", " ["one" "two" "three"]))
to the same affect but more readable you could also use clojure.string/join
Yeah, actually I was trying to do clojurescript koans, and it wouldn't accept an answer with c.s/join
what is the name of clojure tool to visualize edn ?
that one from cognitect to visualize clojure data
Ah, ok. I would call that rather a "data browser" 🙂
Hello, can defaults in destructuring (`:or`) be used with namespaced keywords? https://clojure.org/guides/destructuring#_namespaced_keywords does not mention it and none of :person/or {age 0} / :or {person/age 0} / :or {:person/age 0}
seems to work. So I guess I have to use old good (or age 0)
inside the function body. Right?
The keys of :or are the local symbol names
Which protocol/interface defines dissoc? I cannot see any 😞
I think it’s IPersistentMap
Yeah, it’s called without
there
I'm writing a blog post about the origin of complexity where I want to use one slide from Rich Hickey's talk Simple Made Easy. I don't know how to get into contact with Rich, but maybe @alexmiller can ask him? I will link to the talk also and give him all the credits!
Rich said that was ok
Thanks! It's on Medium, not a personal blog. One example is this one: https://medium.com/@joakimtengstrand/the-polylith-architecture-1eec55c5ebce
I have posted it now @alexmiller. You may also send a special thank to Rich Hickey from me if you see him, he has been a great inspiration!: https://medium.com/@joakimtengstrand/the-origin-of-complexity-8ecb39130fc
there are reporting hooks in clojure.test, not sure if they are sufficient to do this off the top of my head
@gtzogana I've solved this problem in https://github.com/borkdude/advent-of-cljc where the run time of each solution (= test) is recorded into a database.
@gtzogana I wrote my own time macro which returns the time took and the return value: https://github.com/borkdude/advent-of-cljc/blob/master/src/aoc/utils.cljc#L99
maybe a better way is to use metadata with the time took on the result value, but that won't work for non IObj
s
thanks! i found this https://gist.github.com/jcf/a1e3781b8c091a00c5d9 which seems to be the most lightweight solution at present
please help
how I can call java.time parseBest
from the clojure code?
https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#parseBest-java.lang.CharSequence-java.time.temporal.TemporalQuery...-
seems like it should be array of java functions because queries
are varargs
@kirill.salykin does (into-array ...)
work?
dunno how to make ref to a function…
(into-array java.time.LocalDateTime/from)
doesnt work
this is example:
`
TemporalAccessor dt = parser.parseBest(str, ZonedDateTime::from, LocalDateTime::from);
if (dt instanceof ZonedDateTime) {
...
} else {
...
}
Maybe I misunderstand it - but it seems like function ZonedDateTime::from
lemme try feels a bit weird to pass clojure wrapper for java function
nope
Cannot cast [L...$eval91504$fn__91505; to
[Ljava.time.temporal.TemporalQuery;
Just a formatter
Thanks, will try
@kirill.salykin you need to wrap your function in a reify
, something like:
(defn fn->temporal-query [f]
(reify TemporalQuery
(queryFrom [_ x] (f x))))
and since the method is varargs, you also need to pass it as (into-array TemporalQuery [...your wrapped fns...])
user=>
(import '[java.time.format DateTimeFormatter]
'[java.time ZonedDateTime LocalDateTime]
'[java.time.temporal TemporalQuery])
java.time.temporal.TemporalQuery
user=>
user=> (def fmt DateTimeFormatter/ISO_ZONED_DATE_TIME)
#'user/fmt
user=>
(def tqs
[(reify TemporalQuery (queryFrom [_ t] (ZonedDateTime/from t)))
(reify TemporalQuery (queryFrom [_ t] (LocalDateTime/from t)))])
#'user/tqs
user=>
user=> (.parseBest fmt "2019-01-02T12:34:56+00:00" (into-array TemporalQuery tqs))
#object[java.time.ZonedDateTime 0x23ee75c5 "2019-01-02T12:34:56Z"]
you can also do this using the MethodHandles interface, not sure if that's cleaner or not
prob no picnic either way
that would be through java.lang.invoke.MethodHandles.lookup().findStatic() here I think
I'd say it's probably not cleaner :) but does avoid the wrapper
Thanks!
getting a static method handle is like (.findStatic (MethodHandles/lookup) java.time.ZonedDateTime "from" (MethodType/methodType java.time.ZonedDateTime (into-array Class [TemporalAccessor])))
but even that needs some kind of cast or coercion to be a TemporalQuery
What’s the best way to parse javascript? Here’s the catch: how to do it in clojure, not clojurescript
I misread it as "What is the best way to praise javascript?" 😄 Sorry, don't have a good answer to the actual question. I don't work with web stuff much. But I guess there are Java libraries that can do it?
I wonder if @U05224H0W's shadow-cljs does any JS parsing?
not sure if it's intended for "other tools" usage, but if you have any luck with it, lemme know, I want to do some JS parsing as well at some point
sure, I will share my findings (if there are any). It’s just an experiment, I may get bored soon and get back to my normal, boring life. haha.
looks pretty useful:
user=> (def prog (.parseProgram (Parser. (Parser$Config.) nil (SourceFile. "foo" "var x = 10;"))))
#'user/prog
user=> (.-sourceElements prog)
[#object[com.google.javascript.jscomp.parsing.parser.trees.VariableStatementTree 0x18245eb0 "VARIABLE_STATEMENT@<foo(1, 1) - foo(1, 12)>"]]
full repro:
$ clj -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "1.10.520"}}}'
Clojure 1.10.1
user=> (import '[com.google.javascript.jscomp.parsing.parser Parser Parser$Config SourceFile])
com.google.javascript.jscomp.parsing.parser.SourceFile
user=> (def prog (.parseProgram (Parser. (Parser$Config.) nil (SourceFile. "foo" "var x = 10;"))))
#'user/prog
user=> (.-sourceElements prog)
[#object[com.google.javascript.jscomp.parsing.parser.trees.VariableStatementTree 0x61bcd567 "VARIABLE_STATEMENT@<foo(1, 1) - foo(1, 12)>"]]
user=> (.-declarationType (.-declarations (first (.-sourceElements prog))))
#object[com.google.javascript.jscomp.parsing.parser.TokenType 0xf27ea3 "var"]
it seems they use loads of classes with public properties, which could be useful to coerce into Clojure maps
This is what I need: if I have a js file with:
var Foo = { First: function() {}, Second: function() {} }
etc.
I need to get Object.keys of Foo, i.e.: want to get a vector in clj: ["First", "Second"]
that seems doable. my use case would be this: https://github.com/borkdude/clj-kondo/issues/90
well that… is way above my head… 🙂 but you sir is very smart person. I’m sure you’d figure this out
well, it's already been done for Java, I just need to get similar information from somewhere about JS... Thanks for bringing this up, now I might have a fun way of doing this 😜
Yeah, I guess sometimes it is worth banging your head around a thing nobody ever done before
I’m still not sure how to get that list, based on the snippet you have posted:
(def prog (.parseProgram (Parser. (Parser$Config.) nil (SourceFile. "foo" "var Foo = { First: function() {}, Second: function() {} }"))))
What do I do next?.-sourceElements returns list of VariableDeclarationListTree
, going down the rabbit hole and doing
(.-declarations (first (.-sourceElements prog)))
got me nowhere 😞
this seems to return the left hand side of the assignment:
(.-lvalue (first (.-declarations (.-declarations (first (.-sourceElements prog))))))
user=> (.-identifierToken (.-lvalue (first (.-declarations (.-declarations (first (.-sourceElements prog)))))))
#object[com.google.javascript.jscomp.parsing.parser.IdentifierToken 0x2d10e0b1 "x"]
look, "x"
🙂OMG… I’m just going deeper and deeper into the weeds of all these classes and it is fucking mind blowing. Now I understand how Clojure community being smaller than number of people working at Google generates so many awesome ideas all the time. Because they don’t have to deal with this terrifying wilderness of OO class hierarchies
I’ve come to real sad and dismal realization that so many very talented people actually have to design, implement and support shit like that. This is fucking waste of human potential. Almost useless carbon footprint on this planet.
I think I have finally got what I needed.
(def listing "var Foo = { First: function() {}, Second: function() {} }")
(def prog (.parseProgram (Parser. (Parser$Config.) nil (SourceFile. "" listing))))
(map
#(-> % .-name .toString)
(.-propertyNameAndValues (.-initializer (first (.-declarations (.-declarations (first (.-sourceElements prog))))))))
=> ("First" "Second")
Holy mother of Alan TuringMichiel, you have my deepest and sincerest gratitude. It would’ve taken me much, much longer to figure this out. Thank you!
This might also be useful: datafy
(clojure.pprint/pprint (clojure.datafy/datafy (.getClass (.-declarations (.-declarations (first (.-sourceElements prog)))))))
user=> (.-literalToken (.-initializer (first (.-declarations (.-declarations (first (.-sourceElements prog)))))))
#object[com.google.javascript.jscomp.parsing.parser.LiteralToken 0x88a8218 "10"]
yeah, pretty coolusing the inspect function on classes that aren't implemented yet, is a pretty nice way for exploring
and then implement every little thing step by step gets a pretty nice parse tree in Clojure
does anyone happen to know how to set the default font when creating an excel sheel with docjure / poi?
@kirill.salykin This might well be one of those times where an existing Clojure wrapper library would be worth using. Either https://github.com/dm3/clojure.java-time (which we use at work) or the newer https://github.com/henryw374/cljc.java-time (which also supports ClojureScript). /cc @schmee
anyone know of a version of https://github.com/github/scientist for clojure?
it's my go-to just like cheshire is my go-to JSON parser (same author), although for async stuff I sometimes use aleph
From testing against a medium volume runtime (10+ mil requests/day), we found that http-kit
was 4+ ms faster than clj-http inconsistently on requests. We tried tuning clj-http to match http-kit performance but we could never achieve the same latency
That said, clj-http is more standard & easily supports hystrix. More likely to work with New Relic instrumentation too. I'd recommend using it unless you absolutely can't afford the latency hit
I have a weird issue: My clojure app works on my dev machine in both repl and compiled. On my server it throws an error when compiled, but repl works fine. This is the error: error macroexpanding clojure.core/fn at (clojure/core/unify.clj:83:18) Any ideas?
that's an old spec bug that's fixed
you must be seeing old version of the lib in one place and new version in the other
org.clojure/core.unify
@alexmiller That might be - the error started today when I added spec to some routines.
somewhere you are specifying a lein-ring
plugin. Make sure you're using 0.12.5 i belive
It sounds likely that the core.unify library being depended upon is different between non-working and working cases.
https://stackoverflow.com/questions/54948986/i-have-an-error-in-clojure-and-leiningen-command
Or one is using Clojure 1.9.0 or later, which introduced stricter syntax checking of Clojure source code, vs. Clojure 1.8.0 or earlier.
that could be too
it's prob pulled in as a transitive dep of the lein-ring plugin as dpsutton says
@hoertlehner is this a public repo?
@hoertlehner Maybe you could post the output of lein deps :tree
in a gist/pastebin of both environments
Most likely lein ring server-headless 5005
has a different dependency tree than lein repl
or lein deps :tree
commands.
Anyone know a way to get lein deps :tree
output that matches what lein ring server-headless 5005
command would use?
also if you construct your artifact using lein ring uberjar
you will get the same deps there as lein ring gives you locally
It is easy to stick with the terminology one first learned the concepts in 🙂
well, could be that this stuff is ported to CLR... I recently discovered a company in a nearby city which has been developing in clojureCLR for over 4 years and I hadn't heard of them before...
During the presentation I catched a glimpse of the guy's Explorer window displaying clojure.spec.alpha.dll ... which was very weird to me 🙂
You have successfully left dependency hell without having to enter any of the 2nd through 9th levels. Congratulations!
9th level = Jackson version mismatch