Fork me on GitHub
#beginners
<
2023-02-20
>
Matthew Twomey00:02:48

I’d like to use the :validate option of cli-tools parse-opts however, I can’t seem to get it to work the way I’d like. I want to use the provided error message when the user neglects to provide the option:

(def cli-options
  ;; An option with a required argument
  [["-s" "--source-name source-name"
    :default nil
    ;; :default-fn #(str "XXXX" %)
    ;; :parse-fn #(str "XXX" %)
    :validate [#(not (nil? %)) "--source-name source-name must be provided"]]
   ;; [nil "--source-region source-region"]
   ;; [nil "--target-name target-name"]
   ;; [nil "--target-name target-name"]
   ])
Is this possilbe? (it seems like validate doesn’t get called when it’s using the default value)

Matthew Twomey00:02:46

Ooooooh :missing keyword. It doesn’t show up in the docs here: https://clojure.github.io/tools.cli/ However I see it in my repl docs now.

stantheman18:02:19

Trying out Spec and had a really tricky exercise (for me) building on some of Programming Clojure by Alex Millar Stuart Halloway & Aaron Bedra. With a simple Ingredient map I had a scale function. I was looking at overflows which could be 'fixed' by subs ' for . But I tasked using Spec or {:pre conds} to limit valid input within *. The Spec work for the function I found really hard. In the end it was only by re-reading several times the Guide To Spec on Clojure site that I realised the (s/and of :args in the s/fdef was tripping me up as the each part was using an active result from the first. The section is 'Spec’ing functions' especially para 'The second :args predicate takes as input... I don't if its me or if this description needs some highlighting or further exposition? I include code snippet with comments as I thrashed out. But I also wondered if there was some REPL type process Ive missed which helps when working out Specs?

👍 2
dgb2318:02:44

This also tripped me up initially. In addition I didn't understand (from reading code) that specs compose entirely bottom up. In a sense even if you don't specifically ask for them. Say you have an attribute spec of A, and a map spec (s/keys) for B. You don't specify in B that you use A (not even as an optional member), but when you validate B and have A in it with an invalid value, then B will be invalid. It makes sense if you try this in a REPL. And I think spec is well designed that way. But I initially didn't internalize this which tripped me up when reading code.

stantheman18:02:00

Thanks @U01EFUL1A8M. Yes and I wondered related to your B spec implies A spec example; I seemed to get spec error reports that only say B is faulty with no trace to the root A invalidity. I tried using libs like expound but not sure I know how to drive this spec 'stack' effect?

2
Timofey Sitnikov18:02:11

I am tripping on something simple, if I have map like this: {:temp 42.6, :dtof 217.0} and I need to get a vector like this: [42.6 217.0] using lambda inside a map, how can I do that. It seems like I should be able to do something like: (map #(vec (get % :temp) (get % :dtof)) raw-set))) but it does not work.

dpsutton18:02:23

(juxt :temp :dtof) gives you a handy function

dgb2318:02:28

When you map over a map, you get entry pairs.

dgb2318:02:46

Like so: [key value]

dpsutton18:02:51

oh you just have a single map? ((juxt :temp :dtof) {:temp 42.6 :dtof 217.0} . Or just [(:temp m) (:dtof m)]

pavlosmelissinos18:02:43

or even (map m [:temp :dtof]) (or mapv if you really want a vector)

dgb2318:02:04

or just use vals

2
dgb2318:02:30

or (map second {:temp 42.6, :dtof 217.0})

Timofey Sitnikov18:02:43

OK, vals is perfect !!!

dpsutton18:02:59

do you care about the order of the values in your map?

☝️ 4
dgb2318:02:46

ah yes, we can't rely on key ordering in regular maps

dgb2318:02:56

my examples may trip you up further

dgb2318:02:42

use one of @U11BV7MTK’s solutions like [(:temp m) (:dtof m)]seems quite declarative

Timofey Sitnikov18:02:46

I tried it, but here is what I got:

dgb2318:02:03

without the map function

dgb2318:02:43

[(:temp raw-set) (:dtof raw-set)]

Timofey Sitnikov18:02:05

The row-set is a sequence of these maps.

pavlosmelissinos18:02:56

(map (juxt :temp :dtof) raw-set) is my go-to idiom in this case

2
Timofey Sitnikov18:02:30

Thats awesome, that seems to work.

pavlosmelissinos18:02:25

it's not the only way, e.g.: (map #(vector (:temp %) (:dtof %)) raw-set) is what you're trying to do #([(:temp %) (:dtof %)]) is invalid because the # dispatch macro does not work like that, it's like trying to evaluate this: ([(:temp x) (:dtof x)])

pavlosmelissinos18:02:08

vectors are callable of course in Clojure but this example is a) syntactically wrong (you're missing an argument in the call) and b) semantically wrong (your intent is not to call a vector but to build it)

pavlosmelissinos18:02:09

Your original attempt: (map #(vec (get % :temp) (get % :dtof)) raw-set))) was also wrong because you need vector instead of vec (`vec` works on a collection but vector is variadic, it builds a vector from its individual elements)

Timofey Sitnikov18:02:17

OK, wow, I was wondering, I thought vec == vector, good explanation.

dgb2318:02:55

For reference:

user=> (read-string "#([(:temp %) (:dtof %)])")
(fn* [p1__196#] ([(:temp p1__196#) (:dtof p1__196#)]))
user=> (read-string "(fn [m] [(:temp m) (:dtof m)])")
(fn [m] [(:temp m) (:dtof m)])

👍 2
pavlosmelissinos18:02:29

> OK, wow, I was wondering, I thought vec == vector, good explanation. @U012GN57FJ9 Most IDEs let you see the signature of the function the cursor is at, consider enabling this feature in yours. It's really useful, especially as you're learning the language

rschmukler19:02:08

Bit of a weird issue... The output of clj -Spath and clj -Stree seems to reference stuff that is out of date (ie. perhaps cached from an old version of the project's deps.edn). Running clj -Mmy-alias also seems to be ignoring my jvm-opts. Invoking cider-jack-in and everything works as expected (despite saying that it's using the exact same arguments that I am running from my shell). I've tried rm -rf .cpcache/ but stuff just comes back still referencing the old versions. Any tips on other places the cache could be (checked all the locations mentioned in https://clojure.org/reference/deps_and_cli#_classpath_caching) or how I could debug this further?

rschmukler19:02:19

-Sforce also results in the same output being generated (ie. referencing old versions that have since been updated)

Alex Miller (Clojure team)20:02:54

there's nothing else cached anywhere for your classpath calculation, so I assume it's actually calculating it differently. presuming it's not something in your ~/.clojure/deps.edn, it would be useful to have the deps.edn and Clojure CLI version you're using, and a more precise description of what seems wrong to diagnose

Alex Miller (Clojure team)20:02:18

if you can't share the deps.edn, then sharing the -Stree (or -Strace trace.edn) would be a good substitute

rschmukler20:02:26

I tried using -Srepro to try and rule out the ~/.clojure stuff

rschmukler20:02:37

DM'ing a few things (can't post publicly, but hoping it helps)

rschmukler20:02:52

Figured it out, was my fault. Sorry to waste your time.

Alex Miller (Clojure team)20:02:21

rubber duck ftw :)

💯 2