This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-07-04
Channels
- # aleph (1)
- # aws-lambda (2)
- # beginners (30)
- # boot (2)
- # cider (7)
- # cljs-dev (65)
- # clojure (130)
- # clojure-denmark (1)
- # clojure-france (1)
- # clojure-germany (2)
- # clojure-greece (1)
- # clojure-italy (19)
- # clojure-kc (2)
- # clojure-nl (12)
- # clojure-poland (1)
- # clojure-russia (11)
- # clojure-spain (1)
- # clojure-spec (20)
- # clojure-uk (176)
- # clojurescript (65)
- # css (3)
- # cursive (8)
- # datomic (26)
- # editors (94)
- # emacs (10)
- # fulcro (66)
- # graphql (5)
- # midje (1)
- # off-topic (48)
- # om-next (2)
- # overtone (1)
- # re-frame (15)
- # reagent (6)
- # reitit (10)
- # shadow-cljs (68)
- # sql (3)
Unless I'm misunderstanding something, clojure spec (s/keys :req-un [::foo ::bar])
is a way to spec a map, but it operates under the assumption that the key name in the map matches the name of the spec definition
I.E. I'd like the keys in my map to be :type
and :text
for example, but I'd like my spec to be defined as (s/def ::button-type ...)
and (s/def ::button-text ...)
(s/keys :req-un [:button/type :button/text])
is close to what you want.
:req-un
means unqualified keys.
So your map would have :type
and :text
and the key-specs for them could be :button/type
and :button/text
-- does that help @samueldev?
Kind of, what are my (s/def)
s in this scenario? (s/def :button/type)
? (omitted double ::
?)
::type
is just shorthand for :this.namespace/type
So it's just a regular qualified keyword.
(for whatever this namespace is)
So you can have two maps with plain :text
keys but different specs.
okay that did it! thanks @seancorfield. just for my understanding, I can still access this spec from another namespace, even if its unqualified?
here's the full code fyi that works now š
(s/def :button/type #{:success :error :warn :neutral :default})
(s/def :button/text string?)
(s/def ::button-opts
(s/keys :req-un [:button/type :button/text]))
(defn button [opts]
(if-not (s/valid? ::button-opts opts)
(do (js/console.error "Failed to render button; bad props" (s/explain-data ::button-opts opts)))
(let [{:keys [text type]} opts
styles (get-button-styles type)]
[:button {:type "button"
:style styles} text])))
The spec is named by the qualified keyword. So ::type
would expand to :whatever.ns/type
and be referred to that way, and :button/type
is just another keyword.
Also ::foo/bar
expands to whatever the alias foo
refers to.
So if you have (:require [quux.thing :as foo])
then ::foo/bar
means :quux.thing/bar
(and the same for aliases created via alias
)
user=> (alias 'foo (create-ns 'quux.thing))
nil
user=> ::foo/bar
:quux.thing/bar
user=>
I also just discovered Orchestra, to allow me to define my function alongside the args + return specs in one spot
There's also https://github.com/gnl/ghostwheel
It can optionally use orchestra under the hood for validation, but it also a has a more pleasant api with the >defn
macro (in my opinion) and comes with some addtional features
@samueldev i use orchestra + expound extensively -- defn+spec
about half my functions, it's a great way to improve error checking
What is the idiomatic way to process a list of things with an f
of side-effects, but grabbing the result? mapv
feels like cheating.
You can use (into '() (map ...))
but mapv
is also idiomatic in that case, imho
(doall (map f coll))
seems better to me. At least when I see it I know why. mapv
could be for any other reasons
(into '() ...)
reverses the input
also '()
can always be replaced with ()
vectors are always better than seqs if you don't need laziness, because they can give you a seq any time you like
I work on OpenCV code. Being based on C++ code, it implies a lot of āoutā mutable parameters.
An example, here edges is the result of applying āCannyā on src and must be instanciated before.
(Imgproc/Canny src edges 100 500)
I want to chain functions in a Clojure classic way.
(->> image
convert-gray
find-edges
(draw-mat panel))
So I wrap functions like this.
(defn find-edges [src]
(let [edges (Mat.)]
(Imgproc/Canny src edges 100 500)
edges))
Is there a better way of doing this ?@reborg I did but doto
put the variable in front of the given arguments
or in my case itās at second place.
Do you suggest I write a macro doto
-like ? I always forgot the macro solution.
I see @charles.fourdrignier. Indeed a macro is straightforward:
(defmacro doto-> [expr name & forms]
`(let [~name ~expr] ~@forms ~name))
(doto-> (Mat.) %%
(Imgproc/Canny src %% 100 500)
(Imgproc/ConvertGray src %%))
There is also a little trick for doto
(doto (Math.)
(#(Imgproc/Canny src % 100 500))
(#(Imgproc/ConvertGray src %)))
In the context of https://www.reddit.com/r/Clojure/comments/63le75/clojure_and_graphql/ what about security (get data of different user) and alternatives?
as far as I know security is your job - whatever you plug into the graphql layer
I wish there was something like partial, but shorter in name and more like #()
in terms allowing gaps. Something like (p* + 1 _ 3 _)
which would generate a function of two parameters
in scheme this is cut
#(+ 1 %1 3 %2)
is nearly that
yeah but can't be nested
Also numbering arguments is kinda annoying
shouldn't be hard to implement cut, which is your idea with <> instead of _ to denote args
imho _ is misleading because idiomatically it means "I have to accept this input but I ignore it on purpose" in lisps
@roklenarcic maybe here you can find what you are looking for - https://github.com/rplevy/swiss-arrows
`-<>` in swiss-arrows plays a similar role, but for one value only. It is deprecated because clojure implemented the same thing (plus the ability to pick your placeholder) with the name as->
no - -<> does other weird things, never mind
you're right, -<> is a lot like as->
except it also has a default position
and the package offers some-<> as well
maybe it would be nice to have some-as->
in clojure.core as well
or as-some->
Recently there was a github twitter thread about threading macros. @borkdude shared this as one of the outcomes:
https://gist.github.com/borkdude/af4978cd9849357aed25144369fe007c
Suppose I have a map def
ined in a namespace :foo.bar/thing
but I want to dynamically reference thing
given only a keyword version :thing
. So I need to convert :thing
to :foo.bar/thing
and be returned its value.
I know with functions this is done with a reader #'
but I canāt seem to sort this for a plain-ol-def. Iāve tried something like <quote>:foo.bar/~(name :thing)
as a naive first pass but thatās not the ticket
Couldnāt you dispatch on a multimethod?
Hmmm thatās an idea. I was hoping to just pass around āpathsā and dynamically look up these models (maps) where the namespace of the maps isnāt necessary to encode in the path.
Regardless of the design Iāve become a little curious how to dynmically resolve namespaces lin the same way a #'
works for resolving fn vars
#' is used to access a var given symbol resolution (instead of resolving all the way to the value in the var, as is normal)
so for any foo/bar #'foo/bar gives you the var holding that value, instead of the value
and foo is looked up using the namespace aliases in effect
:foo.bar/thing has itself as a value
keywords are self-resolving, they never point to some other thing
do you want foo.bar/thing ?
anyway, the simplest is (defn foo-bar [k] (keyword "foo.bar" (name k))
if you know it's in foo.bar
(that just gives you a keyword)
There exists def thing {:fizz "buzz"}
in namespace :foo.bar
given :thing
Iād like to dynamically retrieve the value {:fizz "buzz"}
there is no :foo.bar namespace
namespaces don't get named by keywords
asking about keywords here is totally confusing the issue
The keyword is simply a reference in a path and I need to resolve itās value which happens to exist elsewhere in the app (in another namespace)
Iām probably just doing a poor job framing the question, Iām not actually confused about how keywords are resolved or used.
user=> (resolve (symbol (name :clojure.string) (name :join)))
#'clojure.string/join
> in namespace :foo.bar made me think you didn't understand namespaces
I have a path in the shape of [:entity :attribute]
and in this example would be [:thing :fizz]
and I need to resolve that to the value "buzz"
but the path is in namespace a
and knows nothing about where thing
is defined.
this stuff is much easier when you don't try to treat namespaces as containers btw
:a isn't a namespace!
you did it again
anyway, if you just put a hash-map in a def, this kind of lookup becomes much easier
especially if you start adding things at runtime, don't create new def from runtime input, add keys to a hashmap in an atom
a good rule of thumb is anything that uses resolve is hacky and halfway broken
do you mind expanding on this? I've seen some code recently that resolve
s symbols provided via config, and I'm wondering about pitfalls
with regular code, the compiler can tell you if any symbol you are implicitly resolving doesn't exist with resolve, this becomes a runtime error when your function is called this can be OK if you know you are using resolve in a limited way on startup for eg. dep injection, but using resolve should be a special case with an explicit rationale (in a code review a dev should be able to explain exactly why they are using resolve and not something more mundane), since resolve can make code very brittle
Yeah Iām thinking instead of trying to force this to work Iām just going to backup and refactor this part of the app to get myself out of this corner.
Iām fairly sure Iāve still not adequately painted a picture of what Iām trying to solve here, which is a smell enough in itself.
If code canāt be easily described, itās probably too complicated/broken and needs to be rethought anyway.
Recently there was a github twitter thread about threading macros. @borkdude shared this as one of the outcomes:
https://gist.github.com/borkdude/af4978cd9849357aed25144369fe007c
@hyankov In hindsight I think this is better: https://twitter.com/borkdude/status/1011164750523326465 No need for hybrids that way.
@borkdude Thanks, I remember the morning I saw this tweet. Playing in the REPL trying to disprove you (unsuccessfully) was a great start of the day š
also it's good to remember how dumb form rewriting macros are - they really don't care what's in them
user=> (->> (+ a b) (let [a 10 b 32]))
42
as->
is intended for use inside ->
, not standalone š
It seems within a defn, I canāt require something and then immediate use it, right?
not without hacky things like resolve
Figures. My use case is to be able to use the swing inspector as needed in the repl, without having the require left at the top level. Right now Iāve just put everything in a comment block and I require as a first step. I can live with it.
It's hard to give relevant opinions without knowing more context - like objectives and constraints.
I guess in general I wonder about how best to handle exceptions at the interface level. In clojure its all dynamic so I just document and move on, but in java stuff like JSONException
is checked so I need to declare, rethrow, or use sneakythrows. It always feels like its bad to expose exceptions like that other parts of the code, but I can't put my finger on why, nor do I know the prevailing opinions.
First time back in a while using clj
instead of lein
. Trying to do the CLJS quickstart but getting cp: PREFIX/example-deps.edn: No such file or directory
. Any pointers? (set up on via from brew install clojure
)
(canāt seem to find whatās looking for that example-deps.edn
file, not sure what module/repo the call is coming from)
seems to be something up in the brew-install
er itself: https://github.com/clojure/brew-install
Sounds weird. I have not heard anyone having issues. Did you brew doctor
?
I would do that, then uninstall completely, then install again
That gets replaced during install
Or at least, when it works it does