beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
seancorfield 2020-09-18T00:18:13.004900Z

@curiouslearn clojure -m entry.point assumes you have the source of project at hand (i.e., on your production server), and that the Clojure CLI is installed (on your production server), and that you are running it in the project directory. This is a reasonable approach for example if you have your code checked out from version control on the server and you deploy new versions by running git pull on the server (which some people do) and just just restarting or reloading your project. java -cp the.jar clojure.main -m entry.point assumes you have a JVM on the production server (which you must have for the Clojure CLI too) and that you have the.jar on the server -- but you don't need the project structure (source code) and you don't need the Clojure CLI installed.

seancorfield 2020-09-18T00:19:20.005600Z

In the latter case, you could build the.jar somewhere else and deploy just that file to the server (by whatever method you choose).

seancorfield 2020-09-18T00:24:33.009600Z

We have one project in production that is deployed as source (legacy ColdFusion code that loads Clojure code at startup -- so we have Clojure CLI installed, plus all our Clojure source code, plus all our CFML source code). All our other projects are deployed just as AOT'd JAR files, and even tho' they all have a primary entry point, several of them have multiple -main functions (in different namespaces) so java -jar uberjars/worldsingles.jar runs a default process (built with depstar and -C -m worldsingles.publisher) but that JAR has dozens of -main functions and all those others are run via java -cp uberjars/worldsingles.jar clojure.main -m some.process for the various namespaces. That's mostly how we run our cron jobs, for example.

šŸ‘€ 1
Test This 2020-09-18T00:40:41.009700Z

Awesome! Thank you. It is all much clearer now. I have so far always deployed using git pull. This has been really helpful.

seancorfield 2020-09-18T01:25:19.010300Z

You're already doing things (one of) the Clojure way then šŸ™‚

seancorfield 2020-09-18T01:25:59.011100Z

(having the Clojure CLI installed on your servers can be useful for all sorts of ad hoc server maintenance tasks so that's definitely a path to consider)

seancorfield 2020-09-18T01:27:47.012400Z

Oh, and one final thing about JAR files that may not be obvious: java -cp the.jar clojure.main with no additional arguments will start a plain console REPL, with everything in the JAR file as your available dependencies. That can be useful too at times.

Josef Richter 2020-09-18T08:05:15.016100Z

Big Sur installation ā€“ can you guys help, please? Iā€™m getting this error, despite having latest command line tools etc.

==> Installing clojure from clojure/tools
==&gt; Downloading <https://download.clojure.org/install/clojure-tools-1.10.1.561.tar.gz>
Already downloaded: /Users/josefrichter/Library/Caches/Homebrew/downloads/e7ac82ad2d40c6edab636f088e6ea8c92552eb07eb1736d0e36d55818e6bc4e7--clojure-tools-1.10.1.561.tar.gz
Error: Your CLT does not support macOS 11.0.
It is either outdated or was modified.
Please update your CLT or delete it if no updates are available.
Error: An exception occurred within a child process:
  SystemExit: exit

Panagiotis Mamatsis 2020-09-18T08:09:10.017900Z

Good morning everyone! Nice to meet you all! I want to start learning a new language and I am thinking about Clojure. I have functional programming background. The purpose of learning it is to use it in my existing company's stack. We are a JVM company. Any good book for the newcomer?

2020-09-18T08:17:19.018Z

this is a brew exception. check brew doctor it usually has some useful information.

Josef Richter 2020-09-18T08:20:17.018300Z

ah, it tells me Iā€™m out of luck, basically šŸ™‚

2020-09-18T08:21:12.019100Z

maybe check if xcode-select -p points to most recent command line tools

alpox 2020-09-18T08:21:24.019600Z

@pmamatsis as I heard there are many good ones. I really liked https://www.braveclojure.com/ and you can read it online for free

Josef Richter 2020-09-18T08:21:35.019700Z

that gives me /Library/Developer/CommandLineTools

2020-09-18T08:22:02.019900Z

but CLT for beta releases usually has ā€œBetaā€ substring in path

Josef Richter 2020-09-18T08:22:14.020100Z

I have clean install of Big Sur at the moment, so I shouldnā€™t have any older CLT.

Josef Richter 2020-09-18T08:25:09.020300Z

I even downloaded the latest CLT published yesterday

2020-09-18T08:26:00.020500Z

aha, then I can recommend to install xcode12 and point xcode-select to itā€™s CLT. Unfortunately apple forces beta users to install xcode to have up-to-date tools(

Josef Richter 2020-09-18T08:26:39.020700Z

> point xcode-select to itā€™s CLT how do I do that please?

Josef Richter 2020-09-18T08:28:15.021300Z

I mean, how do I find out where exactly to point it? should I see two separate installations of CLT?

2020-09-18T08:28:17.021500Z

xcode-select -s /Applications/Xcode.app/Contents/Developer

2020-09-18T08:29:06.022200Z

only replace http://Xcode.app with whatever you vave installed as Xcode12

2020-09-18T08:29:18.022500Z

it could be http://XcodeBeta.app or something else

michele mendel 2020-09-18T08:30:15.023200Z

I can also recommend Brave Clojure. I also read https://pragprog.com/titles/roclojure/getting-clojure/, but it doesn't go as deep in the material as Brave. Next book will be https://pragprog.com/titles/vmclojeco/clojure-applied/, since it talks about working on a project.

Josef Richter 2020-09-18T08:31:04.023400Z

well at this point itā€™s actually official Xcode 12 distributed via appstore. Itā€™s not beta anymore. Only Big Sur is beta. So I ran the command you gave me, which probably didnā€™t cause any change, and the problem unfortunately persists šŸ˜”

Josef Richter 2020-09-18T08:31:28.023600Z

damn apple betas šŸ™ˆ

2020-09-18T08:31:49.023800Z

I was planning to upgrade this evening )

Josef Richter 2020-09-18T08:32:18.024Z

well be careful. I had to wipe clean my macbook and it took 6 attempts to install successfully šŸ˜„

2020-09-18T08:32:40.024200Z

why wipe? is it required now?

Josef Richter 2020-09-18T08:33:34.024400Z

my installation broke down and in recovery mode I was unable to unlock filevault, despite knowing the password. seems like very unfortunate bugā€¦ so the only way was to wipe clean and run clean install

Josef Richter 2020-09-18T08:33:50.024600Z

luckily I have everything important in Dropbox, so no big deal

2020-09-18T08:34:12.025400Z

good to know! will do a backup right before

šŸ‘ 1
Josef Richter 2020-09-18T08:34:12.025700Z

well, I donā€™t really have anything important in the first place šŸ˜„

alpox 2020-09-18T08:34:31.026800Z

@michelemendel oh clojure applied looks great! Gotta put it on my to-read list

Josef Richter 2020-09-18T08:34:50.027100Z

they released beta7 today. so maybe it will be better again

2020-09-18T08:40:16.028Z

The Command Line Tools package for Xcode 12.2 beta isnā€™t currently available. (69012274) I found this in known issues for beta7 (

šŸ™ˆ 1
practicalli-john 2020-09-18T09:22:50.030Z

https://practicalli.github.io/ has books and 80+ hours of videos to help learn the Clojure language and development with Clojure. Content regularly added... Feel free to ask questions about the content in #practicalli

2020-09-18T10:49:54.030500Z

hmā€¦ I think it is possible to install everything manually you need this https://download.clojure.org/install/clojure-tools-1.10.1.561.tar.gz unpack cd clojure-tools ./install.sh /usr/local

Josef Richter 2020-09-18T10:58:15.030700Z

aah that opens its own set of problems with /usr/local not being writable, and cannot be changed

2020-09-18T10:59:53.030900Z

I think prefix is not significant here. It could be any place available for you to write and added to your PATH

Josef Richter 2020-09-18T11:00:31.031100Z

sorry for dummy question, where would you typically put it, please? itā€™s a bit low level for me

2020-09-18T11:09:27.031300Z

do you have ruby installed?

2020-09-18T11:09:45.031500Z

ruby --version should tell you that

Josef Richter 2020-09-18T11:10:18.031700Z

yes, that comes with macOS I think

Josef Richter 2020-09-18T11:10:26.031900Z

2.6.3p62

2020-09-18T11:11:24.032100Z

nice

2020-09-18T11:12:26.032300Z

mkdir -p $HOME/usr/local/Cellar/clojure/1.10.1.561
HOMEBREW_RUBY_PATH=$(which ruby) ./install.sh $HOME/usr/local/Cellar/clojure/1.10.1.561
ln -s "$HOME/usr/local/Cellar/clojure/1.10.1.561/bin/clojure" "$HOME/usr/local/bin/clojure"
ln -s "$HOME/usr/local/Cellar/clojure/1.10.1.561/bin/clj" "$HOME/usr/local/bin/clj"

āœ”ļø 1
2020-09-18T11:14:54.032700Z

then you need to add ā€œ$HOME/usr/local/binā€ to your PATH

Josef Richter 2020-09-18T11:15:28.032900Z

thank you. I fail here:

āÆ ./install.sh $HOME/usr/local/Cellar/clojure/1.10.1.561
./install.sh: line 14: -pi.bak: command not found

2020-09-18T11:16:24.033100Z

I changed my script to support that

2020-09-18T11:16:59.033300Z

sorry

2020-09-18T11:17:05.033500Z

submit solution too early

2020-09-18T11:17:44.033700Z

argh, you also need to run mkdir -p $HOME/usr/local/bin

Josef Richter 2020-09-18T11:21:22.033900Z

you are the king!!!

Josef Richter 2020-09-18T11:21:40.034100Z

thank you, seems to be running!

2020-09-18T11:24:20.034300Z

Nice, glad that it is resolved) later, once everything will be settled on homebrew side, you can simply remove $HOME/usr

šŸ‘ 1
šŸ‘Œ 1
Josef Richter 2020-09-18T11:35:51.034800Z

it all works like charm, running my tiny webapp smoothly now. thank you once again šŸ‘

2020-09-18T11:55:47.035Z

šŸ»

Panagiotis Mamatsis 2020-09-18T11:59:59.038200Z

Thank you all so much for your answers! I will be starting on tonight! Please bear with me! I will come back with more questions! :)

Test This 2020-09-18T12:00:03.038400Z

@pmamatsis I am beginner to clojure too. Since you know Java you are likely in a much better situation than I. But the two I liked are: Clojure Workshop and Living Clojure.

michele mendel 2020-09-18T12:11:47.039600Z

I also recommend listening to Eric Normandā€™s podcasts.

Michael J Dorian 2020-09-18T13:38:19.040100Z

Hey friends, is it typical when building a clojure API to pass data to the (also clojure) frontend as json, or plaintext? Or, is there a way to do edn directly?

2020-09-18T13:40:00.040400Z

check out transit ā€” https://github.com/cognitect/transit-format

Michael J Dorian 2020-09-18T13:40:34.041300Z

Thanks!

2020-09-18T13:48:16.041800Z

Hi! I want to share this GIT repository that might be useful for beginners. This is the useful usermanager example of @seancorfield (https://github.com/seancorfield/usermanager-example/) but for which for learning purposes, I started again from scratch by replacing the Compojure librarie by Reitit and Component by Integrant : https://github.com/PrestanceDesign/usermanager-reitit-integrant-example Cheers!

1
rmxm 2020-09-18T13:58:06.044300Z

So im doing some refactoring work(mostly Im trying to remove unwanted dynamism). I started to run into glorious cyclic dependency problem. It is kind of prominent in clojure since namespaces get initialized with require -> for instance in python import only references a namespace, it gets initialized on first access/invokation from that ref. Is there any sane way of dealing with stuff like this?

alpox 2020-09-18T14:06:46.047400Z

@roguas Im pretty new to clojure but I believe the problem is often the same. Cyclic dependencies often show that things depend on each other which shouldnt. One way this is often tackled is by using a separate namespace for protocols and alike

rmxm 2020-09-18T14:10:23.048700Z

Ive read some discussions regarding this and somehow understand certain underlying problems with that. Problem is that some things are in fact reliant on each other in this way and it is kindof pointless to redesign for compilation only. Like in the python example, you can do

a.py import b
b.py import a

alpox 2020-09-18T14:13:56.050300Z

Yes, that does not work in clojure or as I had the problem too, in golang. One part of me tells me this is good though. The redesign paid out in the end as things got decomplected

alpox 2020-09-18T14:15:48.051700Z

The general way to go is then that different namespaces talk to each other over abstractions from a separate namespace and things which really belong together go in the same namespace

rmxm 2020-09-18T14:19:57.052Z

Is it possible to do require during runtime? I am trying but keep getting Unable to find static field

dpsutton 2020-09-18T14:24:38.052400Z

what are you trying?

rmxm 2020-09-18T14:29:01.056300Z

@dpsutton so currently I can kick the can down the road, by defering requiring a namespace into function. Since the namespace I want available has only one symbol/definition.

; a.clj
(ns a)

(def y 3)
(defn get-x [] 
  (require `(b))
  b/x
)

; b.clj
(ns b (:require [a :as a])
(def x 2) 

rmxm 2020-09-18T14:29:48.057300Z

I am trying to avoid this problem as it currently requires too much refactoring for the chunk I am about to clean up. So I want to defer namespace initialization till a function gets invoked.

rmxm 2020-09-18T14:30:57.057900Z

This way, whenever a/get-x gets called b will already by initialized (so skipped)

dpsutton 2020-09-18T14:33:32.059600Z

someone had a similar problem yesterday. require is runtime but still clojure is trying to compile b/x and there is no b. you can do (requiring-resolve 'b/x) (where b/x is the fully qualified name of x) or, if you're sure that b has been loaded you could just use the fully qualified path. both of these are hacks around the design and fixing that would most likely be your best bet

Panagiotis Mamatsis 2020-09-18T14:38:57.061200Z

Can someone please explain what is the difference between actors and agents? I can't quite understand the difference.

alexmiller 2020-09-18T14:55:15.061800Z

https://clojure.org/about/state#actors

alexmiller 2020-09-18T14:56:19.062400Z

probably helpful for perspective

rmxm 2020-09-18T15:27:33.062500Z

Still kinda stuck is this the way to go?:

; a.clj
(ns a)
(def y 3)
(defn get-x [] 
  (requiring-resolve 'b/x)
  b/x
)

dpsutton 2020-09-18T15:27:54.062700Z

check the docstring on requiring-resolve

dpsutton 2020-09-18T15:28:17.062900Z

it returns the var and then you would use it. (let [f (requiring-resolve 'b/x)] (f))

2020-09-18T15:40:32.065700Z

If I eval a symbol without any namespace: (eval '&gt;) (defn f [] (+ 1 1)) (eval 'f) To my surprise, eval does the right thing: it finds clojure.core/&gt;, and finds my.namespace/f Is there an article on how clojure resolves symbols? Would love to read it!

alexmiller 2020-09-18T15:42:20.066300Z

well Clojure wouldn't work if eval didn't do the right thing, so that should be surprising :)

šŸ˜† 1
alexmiller 2020-09-18T15:42:58.066700Z

you are always in a current namespace per *ns*

ā¤ļø 1
alexmiller 2020-09-18T15:43:15.067100Z

that namespace has a set of "referred" names, aliases, etc

alexmiller 2020-09-18T15:43:53.067600Z

(find-doc #"ns-") to find a bunch of functions that let you explore that info (ns-refers etc)

alexmiller 2020-09-18T15:44:32.068100Z

importantly clojure.core is auto-referred by ns so everything in core is always available unqualified

ā¤ļø 1
2020-09-18T15:48:24.068900Z

Ah, I see, thanks Alex! Will poke around with (find-doc #"ns-")

seancorfield 2020-09-18T16:06:01.069Z

This is why I stopped upgrading my Mac and stayed on 10.12 but now a lot of new software won't install because it's too old šŸ˜’ So I'm switching to Windows and WSL2. So tired of Apple breaking my dev environment!

seancorfield 2020-09-18T16:06:32.069200Z

(and I've been an Apple customer for 30 years!)

rmxm 2020-09-18T16:15:51.070600Z

thanks, (var-get) got me to goodworkable place

2020-09-18T16:17:20.072Z

my mac survived 10.6 -> 10.15.6 of rolling updates of software + Air 2012 -> MacBook Pro 2019 updates of hardware but upgrade XP -> Vista took too much mental energy then I gave up on windows)

JL 2020-09-18T16:19:37.073800Z

Question for the Gurus out there - building a simple API that pulls users info from Datomic. Function in question is this one: First run it returns everything fine, if the database is updated via another call and this function is run again - it seems to be returning cached results. How do I get it to re-evaluate it each run?

(defnĀ find-user-by-username-or-email-allĀ [dbĀ username-or-email]
Ā Ā (d/q
Ā Ā Ā '[:findĀ (pullĀ ?eĀ [*])Ā .
Ā Ā Ā Ā Ā :inĀ $Ā ?user-or-email
Ā Ā Ā Ā Ā :whereĀ (orĀ [?eĀ :user/usernameĀ ?user-or-email]
Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā [?eĀ :user/emailĀ ?user-or-email])]
Ā Ā Ā db
Ā Ā Ā username-or-email))

(defnĀ getUserĀ [username-or-email]
Ā Ā (letĀ [idĀ (find-user-by-username-or-email-allĀ dbĀ username-or-email)]
Ā Ā Ā Ā {:idĀ id}))
{
  "id": {
    "user/email": "john...",
    "user/password-reset-sent": "...",
    "user/username": "john",
    "user/send-updates?": false,
  }
}
Now we update username to something else and the getUser still returns:
{
  "id": {
    "user/email": "john...",
    "user/password-reset-sent": "...",
    "user/username": "john",
    "user/send-updates?": false,
  }
}

Josef Richter 2020-09-18T16:19:53.073900Z

@seancorfield itā€™s not that bad, itā€™s just not a good idea to install beta versions of operating systems if you want to be conservative šŸ™‚ so I knew and embraced the risks. but if you find peace and pleasure on windows, then why not. microsoft is making huge leaps in developersā€™ satisfaction.

marshall 2020-09-18T16:23:11.076100Z

@thdm are you passing the same db value each time?

marshall 2020-09-18T16:23:25.076600Z

Datomic db values are immutable

JL 2020-09-18T16:24:25.078700Z

Yes so the input in this case would be (getUser "john")

marshall 2020-09-18T16:24:37.079100Z

So to query for data that has been added since your first call to d/db you need to call it again to get a new db value

JL 2020-09-18T16:26:31.079600Z

I'm not understanding - I have to call the getUser twice?

marshall 2020-09-18T16:26:53.080100Z

No, the call to d/db

marshall 2020-09-18T16:26:59.080400Z

To get a database value

marshall 2020-09-18T16:27:12.080900Z

The db you're passing into the query

marshall 2020-09-18T16:28:10.081800Z

Give me a minute I'll make an example

JL 2020-09-18T16:28:26.082100Z

db is defined as:

(def uri (:datomic-url e/env))

(def conn (d/connect uri))

(def db (d/db conn))

marshall 2020-09-18T16:28:47.082500Z

Right. That value of db is immutable

marshall 2020-09-18T16:29:12.083300Z

It is a db value as of the exact moment you called d/db

marshall 2020-09-18T16:29:52.084500Z

So anything you transact into the db after that point in time will not be in that original db value

JL 2020-09-18T16:30:37.084800Z

so I have to redefine db each call then?

marshall 2020-09-18T16:31:39.086200Z

It depends what you're doing. You may want to keep a specific db value for several operations

marshall 2020-09-18T16:32:04.087300Z

So that you know they're all using the same consistent point in time db value

JL 2020-09-18T16:32:29.087900Z

aww ok - got a code snippet to re-evaluate db each call? LOL omg.

JL 2020-09-18T16:33:44.088500Z

In this case I want the latest - basic CRUD operations

seancorfield 2020-09-18T16:36:21.088700Z

@delaguardo I've only become a fan of Windows since 8.1 (but I've been forced to use every version since 3.11). I've always had Macs. I started on 680x0 chips, went through the PowerPC migration, the Intel migration. I've had over half a dozen laptops and over half a dozen desktops. Back in the System 6 & 7 days I ran MachTen (Tenon Intersystems' BSD variant) as a "parasitic" Unix O/S alongside Apple's O/S so I've always had the "Mac" interface and *nix under the hood. But almost every single O/S upgrade broke something in my dev setup and over the last 5-8 years Apple seem to have lost interest in developers and swung their focus squarely to consumers and services. I used to absolutely hate MS but over time I found myself preferring their apps on my iPhone, and I bought a cheap Windows laptop in 2012 that has slowly become a more usable developer machine. This year I replaced my iPhone with an Android, and I just bought a Surface Laptop 3, and I hadn't realized just how much of a "captive system" Apple has become. I'm pleasantly shocked at how much MS has embraced open source and how much they are focusing on developer experiences these days.

seancorfield 2020-09-18T16:37:49.088900Z

With WSL, I run Ubuntu for all my dev work on both laptops, while still having the slick UX of Windows 10. I never thought I'd switch from a Mac, when I bought my last iMac in 2012...

marshall 2020-09-18T16:40:27.089400Z

if that's the case, you can pass (d/db conn) to your call to your query function

marshall 2020-09-18T16:40:30.089600Z

instead of passing db

JL 2020-09-18T16:43:10.090200Z

So like this?

(defn getUser [username-or-email]
  (let [db (d/db conn)
        id (find-user-by-username-or-email-all db username-or-email)]
    {:id id}))

marshall 2020-09-18T16:43:19.090400Z

sure that works too

marshall 2020-09-18T16:43:25.090700Z

i might still make db an argument

marshall 2020-09-18T16:43:32.091Z

otherwise you'd have to pass a conn

marshall 2020-09-18T16:43:36.091200Z

which is less idomatic

JL 2020-09-18T16:43:40.091400Z

Ok I get where I went wrong

marshall 2020-09-18T16:43:44.091500Z

so leave your getUser function alone

marshall 2020-09-18T16:44:04.092Z

and just change where you call it from: (getUser db ...) to (getUser (d/db conn) ...)

marshall 2020-09-18T16:44:53.092300Z

ah, sorry i misread your original; That advice ^ still stands though

marshall 2020-09-18T16:45:12.092800Z

but having getUser do the "getting a db value" is probably OK too

marshall 2020-09-18T16:45:19.093100Z

is your conn a global var?

JL 2020-09-18T16:45:23.093400Z

yah

marshall 2020-09-18T16:45:44.093900Z

generally you'll want to avoid that and pass either a conn or a db value to functions that transact or query, respectively

marshall 2020-09-18T16:46:21.094600Z

i.e. maintain the conn in a map that represents your system context (or use something like the component library to help with it)

marshall 2020-09-18T16:46:34.095Z

then your getUser could take a db and a username

marshall 2020-09-18T16:47:07.095700Z

and you could invoke with something like: (getUser (d/db (:conn my-ccontext-map)) "username i care about")

JL 2020-09-18T16:49:55.096600Z

Re-arranged it to

(defn find-user-by-username-or-email-all [db username-or-email]
  (d/q
   '[:find (pull ?e [*]) .
     :in $ ?user-or-email
     :where (or [?e :user/username ?user-or-email]
                [?e :user/email ?user-or-email])]
   db
   username-or-email))

(defn getUser [db username-or-email]
  (let [id (find-user-by-username-or-email-all db username-or-email)]
    {:id id}))

(GET "/getuser/:n" []
  :path-params [n :- s/Str]
  ;:summary ""
  (ok (getUser (d/db conn) n)))
)))

marshall 2020-09-18T16:52:20.097900Z

:thumbsup: looks much better consider looking into conn management stuff in the future (i.e. the conn not being a top-level var, but instead created by a function call and passed around as needed) see: https://github.com/Datomic/ion-starter/blob/master/src/datomic/ion/starter.clj

marshall 2020-09-18T16:52:55.098800Z

both the peer library and client library cache connections, so you can safely write a "get connection" function that you can invoke from wherever in your application

marshall 2020-09-18T16:53:00.099Z

and you will get back the same connection

2020-09-18T16:53:18.099100Z

I always have archlinux aside from other, more user friendly, OS. That is like steel hardening - I saw so many problems during software upgrade, now they don't bother me at all) maybe you right and Apple is not doing great job for developers, but I just can't share same feeling, probably because of some different usage patterns. But let's do not convert this thread into a battle of vendors our operating systems. Someone had annoying problem, was aware of consequences of beta testing and ask for help - I would never try to convince trying something completely different because of such a minor thing) :cheers:

marshall 2020-09-18T16:54:46.100200Z

there is a little bit of extra stuff in that example ^ for ions But you could just as easily have a get-conn function:

(defn get-conn
 (d/connect "my-datomic-uri"))
in a peer

seancorfield 2020-09-18T16:55:48.100700Z

Indeed šŸ™‚

JL 2020-09-18T16:56:33.101300Z

Gotcah - Thanks a ton - that solved a couple days of head pounding.

marshall 2020-09-18T16:57:30.101500Z

:thumbsup:

seancorfield 2020-09-18T17:06:58.101600Z

I should try Arch some day. I hear lots of developers using it and liking it.

james 2020-09-18T19:27:24.104700Z

Hi! I was wondering if there is a way to get left-over keys from an s/keys spec. For example, if I have (s/keys :req-un [::name]) and the map {:name "Alice" :age 34}, and if it's s/valid?, I would like it to return {:age 34}. Is there something in Spec that does this? (I don't want to prohibit extra keys, but I'd like to know what they are, if provided.)

james 2020-09-18T20:09:00.104800Z

(I was able to hack something together using s/describe.)

vncz 2020-09-18T20:44:22.105Z

@johsgrd I'm curious about your solution, can you post it?

james 2020-09-18T20:47:40.105200Z

Sure. But it's terrible. And also doesn't handle req-un vs req and opt-un vs opt.

(defn all-keys
  "If given SPEC is a keys spec, return all the keys it knows about."
  [spec]
  (let [form (s/form spec)
        [kind &amp; options] (and (seq? form) form)]
    (when (= kind 'clojure.spec.alpha/keys)
      (set (mapcat (apply hash-map options)
                   [:req-un :opt-un :req :opt])))))

(defn leftovers
  "If SPEC is a keys spec and X conforms to it, return left over keys."
  [spec x]
  (when (s/valid? spec x)
    (when-let [keys' (all-keys spec)]
      (let [extra-keys (set/difference (set (keys x)) keys')]
        (zipmap extra-keys (map x extra-keys))))))

dehli 2020-09-18T21:46:39.106200Z

Thereā€™s also https://cljdoc.org/d/metosin/spec-tools/0.10.4/api/spec-tools.core#select-spec which does the opposite of what you need. Itā€™s a pretty cool library!

šŸ‘ 1