This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-05-26
Channels
- # announcements (7)
- # babashka (42)
- # beginners (349)
- # chlorine-clover (9)
- # cider (16)
- # circleci (2)
- # clj-kondo (6)
- # cljs-dev (61)
- # cljsrn (15)
- # clojure (95)
- # clojure-europe (11)
- # clojure-italy (2)
- # clojure-nl (4)
- # clojure-spec (4)
- # clojure-uk (24)
- # clojurescript (21)
- # conjure (2)
- # core-async (8)
- # cursive (12)
- # datascript (2)
- # emacs (4)
- # exercism (1)
- # figwheel-main (86)
- # fulcro (27)
- # graalvm (4)
- # helix (36)
- # hoplon (3)
- # interop (44)
- # kaocha (6)
- # lein-figwheel (4)
- # malli (7)
- # meander (9)
- # off-topic (95)
- # pathom (33)
- # pedestal (13)
- # re-frame (20)
- # reitit (3)
- # shadow-cljs (102)
- # tools-deps (14)
- # xtdb (16)
I would like to try the next part (about REPL), but how do I get control of the cmd prompt again? C-c doesn't work.
Of course right after I posted that I tried Ctrl-c for the 4th time and this time it worked. š
@seancorfield In case you're wondering how that bit of extra text was stuck on the end of the line (that caused my error earlier), I just saw it happen again, and it's because I when I select text and then paste text from the clipboard I expect the pasted text to REPLACE the selected text, not just shove the selected text to the right. Another Emacs gotcha.
Strange, though. If I just wanted the original text pushed to the side I would have simply put the cursor to the left of it before pasting. I don't see how selecting a region before pasting could indicate anything other than that the user wants text replaced.
Emacs is all about infinite customization. The defaults are from the 50s, so they're not really intuitive to our modern era. I'm sure there was good reasons back then, but this is so far into the past, you need to undertand that even keyboards had different layouts and keys, screens were super small, there was no mouse, etc. So who knows why that's the default behavior they thought was most useful
But like I said, Emacs value is in customizing it to your liking. In Emacs, you can change absolutely everything, and you can very easily add whole new features. That's the selling point. Some people hate that. They don't want to customize anything, they want someone with good UX design skills to come up for them with the best set of features, shortcuts, etc. But others love coming up with their own.
Is there any threshold past which a change to Emacs' defaults would ever be made? Case in point.
If you like to customize things though, Emacs makes that really easy. Powerful customization that would require a whole team of paid developers in other programs can be made by one person as a side project in Emacs.
Hum.. in what sense? You're using Doom correct? Have you ever tried default Emacs š, Doom already changes like a million things.
If you re interested by the way, this is what you can put in your emacs config. I use Spacemacs, not Doom, so I'm not sure where exactly it should go with regard to Doom. I'd say if there's a place for added user config in Doom try it there.:
;; Make it so when text is selected, and you paste, it replaces the selected
;; text, instead of pasting before the selection and keeping the selected text.
(delete-selection-mode 1)
"The defaults are from the 50s" -- 1976, actually, @U0K064KQV
GNU Emacs dates from the mid-'80s.
But, yeah, it's weird stuff like the above that made me glad to leave Emacs behind and switch to a modern editor š
@didbus Yeah, given what you said about Doom being customized to the nth degree, it is kind of strange that that paste-beside-instead-of-replacing-selected-text behaviour wasn't changed in Doom.
and thanks for this: "
;; Make it so when text is selected, and you paste, it replaces the selected
;; text, instead of pasting before the selection and keeping the selected text.
(delete-selection-mode 1)
I'm sure once my self-imposed probationary period is over and I allow myself to start tweaking things, that will be near the top of the list.Ya I agree. In Spacemacs as well I had to change it myself. I wonder if that's the default Vim behavior? Because both Emacs and Doom try to re-implemented the Vim behavior
I actually wish there was a Spacemacs/Doom for Emacs but not focused on Vim/modal. But more focused on just providing a modernized well put together behavior.
Again, though, highlighting text (instead of just leaving the cursor beside it) is just an extra step that I can only imagine would ever be done to get a different behaviour than just pasting beside. i can't imagine why else anyone would do it.
@U0K064KQV Have you tried xah-fly-keys?
I heard about it, didn't try. That one seems even more "weird" :p. Like it's trying a whole different thing. I'd just want a normal one.
I mean, it's okay, I use Spacemacs as a base, and have changed things to my liking. So now it's pretty normal
Sounds amazing to me, though. Most common functions on easiest-to-reach keys. Loses mnemonicity though. lol Then again I'm not yet convinced Emacs commands are very mnemonic.
That's reason #2 I specifically DID like the idea of an EVil-based distro. (Is distro the right word?)
vim is pretty mnemonic, from what I remember from a 1 or 2 day crash course I took alongside my 1 or 3 week Emacs crash course last year.
For now I'm not using EVil in Doom yet though. lol I've already biten off a lot to chew for now.
Ya, I don't like the Emacs bindings, but I also don't like the Vim ones or modal editors in general
Its like, ok, x and text rhymes. And there's an x in text. But you kind of just have to learn it
Spacemacs is modal by default. But you can use it in non modal. In which case ya, SPC is no longer the leader, instead by default on non modal it's M-m
I found it because I thought SpaceMacs looked great, then I figured I should ask if there are any other 'distros', heard about Doom and xah-fly-keys (/Ergomacs?), and then found this post:
I have ESC and M-m both as my leader. Since ESC doesn't do anything useful in Emacs, it's a nice way to have a single leader without modal
So if you don't like modal editors, then you are not using the SPC leader? You basically are using Mmmacs?
Haha lol ya. And since I've got it on Escape as well I thought about calling it Escapemacs lol
Well aren't you usually in a buffer that is editable, where SPC would just insert a space? I don't get how you would get much use out of SPC as a leader key. Wouldn't you have to use M-m most of the time?
Oh ya, in non modal you can never use SPC as leader, well I mean... You could lol. Like you could make SPC SPC be insert a space, and SPC be leader. But I think you'd want to insert a space more often than you'd want to run a command
The only downside is it doesn't work in terminal Emacs, because terminals are another thing from the 50s (or 70s?) which are so archaic that escape and alt were the same thing. Anyway. I don't use it on terminal. So I don't mind
Actually I think I'd like M-m more as a leader. It's easily reachable from home row finger placement and doesn't use either pinky.
Oh yeah. I just remembered the other thing on the top of my customization to-do list: Making Esc Esc Esc NOT destroy most of my window panes.
Ya M-m works pretty well. It seems I've naturally made is so for some commands I use M-m and others I use Esc. Like there are commands that when I run, my hands are rarely even near the keyboard, like opening a new file. So I seem to use ESC for that. While for things that are more editing where my hands are already near the center keys I'll use M-m
Or rather Heinrik, the very helpful creator of Doom, pointed out to me that for winner-mode actions I have to use the EVil version of the commands.
"I've naturally made is so for some commands I use M-m and others I use Esc" That sounds next-level. Nice.
Also M-x is the command pallete default keybinding, so M-m as the shortcut based variant makes sense
Ya, I've been wanted to try Doom, it looks well done. But I have no reason to leave Spacemacs, works great for me. And I'm a bit worried Doom in non-modal won't work as well
I'm also always tempted to create my own config from scratch where I could choose every single shortcut to exactly what I want haha, but I know that would be a huge waste it time
Like you don't use Vim shortcuts when editing, like say i to insert and esc to go back to navigating, and moving around with hjkl ?
I don't know if you can just turn EVil off, but I did discover (the hard way, while trying to undo with Ctrl-z, that C-z toggles it on and off while in a buffer
Except instead of Using C-x C-f to open a file, I am tending to C-z into EVil mode, then use SPC .
winner-mode is on by default, which is GREAT because having my window pane arrangement blown away by accidentally hitting Esc Esc Esc is insanely annoying.
"Also, for evil users its keys are on C-w u and C-w C-r If you're not using evil it, it has no keys by default. Something I'll need to fix Oh wait. It's on C-c w u and C-c w U"
I'm not sure where I would look up what other things like that exist. Maybe the EVil mode keys are all in a list somewhere (the documentation for EVil I guess). Maybe the list for non-EVil use of Doom is even harder to find.
Bedtime. Talk to you again sometime. If you do end up trying Doom, let me know! Now that would be interesting. A more advanced Emacs user and a noob with a bit of a head start trying to learn it at the same time. lol
In general, in Emacs, you can use C-h b and search for commands and it'll show you all the bindings
So far the use of C-h I knew is that in Doom, if you can't see the whole menu after pressing the leader key (SPC), in order to see the other page(s) you have to press C-h and then j or k.
I have already suggested to Heinrik that being able to scroll through by just pressing SPC more times would be nice. š
Which is the plugin that shows the list of bindings following a leader key. Spacemacs also uses C-h but then it's n and p or j and k
The reason is that, C-h is kind of reserved. No one will ever overwrite C-h because it's the help keys
If my suggestion gets implemented in Doom, it might have more claim to the Spacemacs name than Spacemacs does. lol
If you press C-c the list shows up, and typing SPC now cycles the list, but you want to execute C-c SPC, you're stuck
Anyways, it's probably a one or two liner for you to configure yours to cycle with SPC instead
It could even be in the list ("SPC <that other action> unavailable. Use C-c SPC to access")
I guess in Spacemacs they prefer having SPC SPC as a convenience for the command menu
Don't know about what a command menu. That's not tlike the thing that comes up when you press SPC in Doom?
But that's where my complaint was coming from. Both Spacemacs and Doom are from people who prefer Vim
That's actually a good idea for cycling the list with arrow keys, I might actually add that to my config š
Haha, for sure. I mean Clojure doesn't try very hard to be user friendly and familiar and intuitive, but Emacs takes it next level š
A menu of options and not having to look up keys elsewhere was a big selling point for me picking Doom. Being met with a partial list I couldn't figure out how to scroll was so bad.
I have Ctrl, shift and alt and some combination of them + arrow keys setup for overall navigation of most things. So like I move my cursor around code with that, and I switch between windows with that, and I switch between buffers, etc.
I did reach for the right arrow key, and C-right, and M-right, and C-M-right, and all those combinations with Shift. One of them should have worked.
Anyways, you'll see, eventually the fun begins when you start to understand how to change things to how you want them yourself :p
Once you know Clojure, learning Emacs Lisp isn't so hard. Since they're both a Lisp, Clojure already got you 90% of the way. That's what happened to me
I know I'm going against a bit of advice by going for CLJS before Clojure. Hope that doesn't hurt me too badly.
I mean I at least used vim for a couple of days, and Emacs for a couple of weeks, and did a ClojureScript program (just basically following the quick start guide and no tooling except maybe Leiningen), but that was all a year ago...maybe two.
I think part of my optimism is from trying out Blender instead of easier to learn tools for 3-D modelling and video editing and having been happy I went that way.
Facing too many challenges early on, sometimes it's demotivating. And people can get the impression things are complicated, don't work well, etc.
Haha, ya I had people say they learned it all together. Emacs, Clojure, ClojureScript, programming all at once. And they found it more fun like that
I had read the same thing about Blender...designed for maximum productivity in the end state, though harder to learn.
Ya, while I'm actively focused on a project, I'm way more productive. Its in-between where I lose a lot of time changing things, trying things out, and customizing things. And once in a while you hit a bug or something temporarily broken. Which can be annoying, but they generally get fixed super quick
Or the fact you know there's always a way to do anything. Like today, I needed to use Emacs from the terminal and have the clipboard sync with the OS clipboard. I could have found some quick way around for my use. But I really wanted to figure out how to set it up
So it did take me 1 hour :p, but now I know, and I have it set up. So if I need this in the future it'll be fast
@dpsutton I got the REPL part of your example to stop spitting out errors, and now I put the bigger version of main.cljs (the one with the React parts) in place, but this time I keep getting:
i.e. With the previous version of main.cljs I was able to get to the point of command prompt giving me the prompt 'app.main=>' and have entering '(app)' there output the div code in your example. ...but I used Ctrl-c to terminate that batch job, then replaced the more basic main.cljs with the more advanced one (the one with React) and now the exact same steps do not work.
O...M...G. Once again my computer makes a liar of me. The socket connection error was the last thing in the cmd window for minutes, but then after I posted the long post above I glanced back at it and now it's done some more things and is giving me the cljs.user=> prompt. Just took forever I guess.
....but now I am getting the "No application has connected to the REPL server. Make sure your JS environment has loaded your compiled ClojureScript code." on entry of (require 'app.main) or (in-ns 'app.main).
That browser has this warning at the bottom, though: "shadow-cljs - Stale Client! You are not using the latest compilation output!"
Open the dev console and hit refresh. Make sure youāre using the latest compilation output and not a cached version
react-dom.development.js:24995 Download the React DevTools for a better development experience: https://fb.me/react-devtools
react-dom.development.js:89 Warning: componentWillMount has been renamed, and is not recommended for use. See https://fb.me/react-unsafe-component-lifecycles for details.
* Move code with side effects to componentDidMount, and set initial state in the constructor.
* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run npx react-codemod rename-unsafe-lifecycles
in your project source folder.
Please update the following components: http://app.main.app
printWarning @ react-dom.development.js:65
browser.cljs:20 š ¶ shadow-cljs: WebSocket connected!
browser.cljs:20 š ¶ shadow-cljs: WebSocket disconnected!
And as for making sure I'm using the latest compilation version and not a cached version...does that mean re-running the command with 'watch' itn it?
Actually I re-ran "npx shadow-cljs watch app", then got it to show up in the browser and it's still the old version of main.cljs that isn't even in the folder anymore. THEN I tried opening it in a completely different browser (FireFox instead of Chrome) and going to localhost:3000 STILL gave me the old version. That would mean it's not a caching issue, wouldn't it?
that shouldn't give you "hi" it should say starting nrepl server on port ... and compiling
[:app] Compiling ... [:app] Build failure: The required JS dependency "react-modal" is not available, it was required by "app/main.cljs".
shadow is very good at providing feedback. make sure to slow down and read what it tells you
in the future i believe you can npm i react-modal
from a separate terminal and the running shadow server will pick it up and start working
------ WARNING #1 - :redef-in-file --------------------------------------------- File: C:\Users\Ady\AdyProg\ClojureScript\20200522_asg_ignite_app\src\app\main.cljs:33:1 -------------------------------------------------------------------------------- 30 | [:li "With content"] 31 | [:li "And lists"]]]]]))) 32 | 33 | (defn app -------^------------------------------------------------------------------------ app at line 7 is being replaced -------------------------------------------------------------------------------- 34 | [] 35 | [:div {:style {:margin "auto" 36 | :margin-top "100px" 37 | :width "600px"}} --------------------------------------------------------------------------------
because that error message is pretty specific: "app on line 7 is replaced here on line 33"
Ahh.. Emacs not bothering to delete selected text during a paste operation got me again. What an insane default.
> When Delete Selection mode is enabled, typed text replaces the selection
if the selection is active. Otherwise, typed text is just inserted at
point regardless of any selection.
try (delete-selection-mode 1)
In the error, the yellow text looks like it is a summary of the block of white text directly below it. Misleading.
I'm sure I would have caught it if the two line numbers in question were highlit (or not) equally. š
just slow down and read is all i can offer. it pasted the offending code overlayed with a warning pointing at the warning.
The only output is "[:app] Compiling ... [:app] Build completed. (82 files, 42 compiled, 0 warnings, 37.77s)"
but really I would need everything in the parent folder (public) to have a complete webpage, it looks like.
so a recommendation for you before i have to go. build three more apps from scratch that do simple things mimicing exactly this template. get comfortable with what things need to go where. how to start the app, how to get a repl up and running
Actually if I point my browser to the index.html file in the public folder, I get nothing.
then, go read the (excellent) shadow documentation explaining what all the options mean. what is an asset-path? what are modules. what are the docs of output-dir. what do the metadata in main.cljs mean
I don't think I tried the REPL with the second, more advanced main.cljs file yet actually. I meant to do that. I will
I think I will want to figure out what CIDER has to do with all this too, then go make some more simple apps, as you say.
So you are running your server through npx shadow-cljs watch <build-name>
and you can view your web app in a browser right? With CIDER you can connect to the nREPL server that the shadow command starts. This lets you send code directly to your app from your editor. If say a function is not behaving how you expect, you can replace it as soon as you write it by sending it right to the app. This way you can either fix the issue or add some logging to help you fix it. You can also evaluate code and get the output in emacs too. For instance calling a function you just wrote with some test data to make sure it returns the expected output. No need to switch to your browser and test it just to make sure it's not broken.
get used to having two terminals. start npx shadow-cljs server
in a terminal and then you can do npx shadow-cljs cljs-repl app
in another terminal
but in general you shouldn't be killing the server. be prepared to have that up and running
Hi fellow clojurians, I wanted to validate a thought process of mine, that solving 4clojure problems will help me win half the battle in learning Clojure and I want to stick by it no matter what time it takes.
I think it helps getting familiar with using the core functions, and to think about how to loop functionally
I found 4clojure very challenging when I started learning. On the other hand Clojure Koans had a much gentler learning curve and I loved the experience. Just throwing it out there.
are you having trouble understanding clojure?
No, solving 4clojure problems which is basically logical
Clojure is the simplest thing to learn, i dont know why we were not introduced to such functional programming in earlier days of our teens, rather than OOPS bullshit
I learnt clojure fairly early and it saved me from way too much pitfalls in java and python š
Lucky you!
I have to agree. I see some people who find Clojureās model hard to grok, but they seem to be programmers used to OOP. I think Java for example is fine, but Clojure is just so clear and simple by comparison. Everything feels like it is directly in your face instead of hidden.
Hello š What's the standard library/way of working with xz compressed files, as in opening for reading or writing? I've been looking around for libraries, but haven't found anything better than java libraries in Apache Commons and a small Clojure example of wrapping that Apache Commons java library. What's the idiomatic/ generally accepted way to do this? Should I wrap external code or am I missing some standard functionality in Clojure?
for this type of task, using java interop along with a java library is probably the way to go. java interop in clojure is pretty good. having access to a wide range of performant and mature java libraries was one the main reasons clojure targeted the jvm
Yeah, I thought I'd have to dive into the interop š What's the standard way of assessing the "quality" of Clojure libraries? Is there a curated list of recommended libraries somewhere?
Well, third party libraries, that is š
thereās https://www.clojure-toolbox.com/ for some definition of curated.
Oh great, thanks š
> Whatās the standard way of assessing the āqualityā of Clojure libraries? Iāve seen a similar question frequently. Iāve always thought you had to just evaluate libraries individually. do other languages have a standard way of assessing the āqualityā of their libraries?
Not sure in general, and people probably would need to build some familiarity of the eco system over time. Common Lisp has https://github.com/CodyReichert/awesome-cl for example, and there is something similar for Haskell.
Hello Clojurians, with lein, there is wrap-reload
for live-reloading during development, and there is a way to specify a development profile, is there a way to accomplish live reloading during development when only using deps.edn
and not lein or boot?
wrap-reload is a middleware for the ring, isnāt it?
with deps.edn you can use an alias to specify development dependencies including extra source-paths
@U04V4KLKC, ok, so I was trying to do something like: https://practicalli.github.io/clojure-webapps/ring-compojure/reloading-the-application/ using deps.edn
. They seem to have the -main
and -dev-main
.
so if you want to have similar workflow I would recommend to create two source root directories: src
and dev
then in deps.edn
{:paths ["src"] ;; common source code
:aliases {
:dev {:extra-paths ["dev"]
:main-opts ["-m" "dev.core"]}}}
you also will need to have in dev
directory core.clj with -main function (same function as -dev-main in your link)
Ahhh, ok, thats how you do it. Does that workflow makes sense? What workflow do you use?
(ns dev.core
(:require [ring.adapter.jetty :as jetty]
[ring.middleware.reload :refer [wrap-reload]]))
(defn -main
"A very simple web server using Ring & Jetty,
called via the development profile of Leiningen
which reloads code changes using ring middleware wrap-reload"
[port-number]
(webserver/run-jetty
(wrap-reload #'welcome)
{:port (Integer. port-number)
:join? false}))
it is totaly fine to have this workflow for small applications but I can suggest to have a look at some component (or system) oriented libraries. such as https://github.com/weavejester/integrant or https://github.com/stuartsierra/component
they give you ability to choose in repl which combination of systemās parts you want to run. this will become more useful when you will start wrapping your head around testability and composability of your application
https://github.com/weavejester/integrant-repl also usefull link
Wow, lots to learn, probably should start simple and then work something like that in. Do you professionally develop in Clojure?
Thats awesome, I do embedded C++ at work. Just began learning Clojure. Getting started is very challenging, there is just so many ways to do something.
welcome) it is challenging especially when you jump into clojure with completely different background but believe me - it will repay you ten times more) also I do recommend to read throw SICP book to get some understanding of sequences and operations on them
So far https://apps.ankiweb.net/ app and http://shop.oreilly.com/product/0636920034292.do have been my best friends. I have been getting up at 5:00 AM and learning Clojure, but should get to SICP soon.
So yes, I am hoping for 10X reward:slightly_smiling_face:
I'll just pop into this thread to say that you can avoid the complexities of reloading if you develop a very tight REPL-driven workflow, where you eval every single change directly into your running app.
I run my REPL for days, sometimes weeks, without restarting and hardly ever even needing to stop/start my Component system. But you do need to be careful to use #'handler
instead of plain handler
when wrapping middleware around your code (so you get the extra indirection that allows changes to be picked up immediately rather than being compiled in once).
Example of #'
usage: https://github.com/seancorfield/usermanager-example/blob/master/src/usermanager/main.clj#L122-L133
@seancorfield I am so new at this that I am having hard time firing up the app in REPEL. So if I do this:
[I] /home/sporty/clojure/usermanager-example~> clj -m usermanager.main 3000
Starting up on port 3000 with server jetty
Exception: [SQLITE_ERROR] SQL error or missing database (table department already exists)
Looks like the database is already setup?
2020-05-27 11:41:00.129:INFO::main: Logging initialized @10153ms to org.eclipse.jetty.util.log.StdErrLog
It seems to work fine, but if I enter REPL, it annot resolve symbol main:
[I] /home/sporty/clojure/usermanager-example~> clj -A:rebel
[Rebel readline] Type :repl/help for online help info
user=> (ns usermanager.main)
nil
nil
Syntax error compiling at (REPL:1:1).
Unable to resolve symbol: -main in this context
usermanager.main=>
I must be missing something simple.You need to require
the namespace before you can use functions from it
@U012GN57FJ9 Did you get it working in the end?
(! 530)-> clj -A:rebel
Downloading: com/bhauman/rebel-readline/maven-metadata.xml from clojars
[Rebel readline] Type :repl/help for online help info
user=> (require 'usermanager.main)
nil
user=> (in-ns 'usermanager.main)
#object[clojure.lang.Namespace 0x6ed1fdb7 "usermanager.main"]
usermanager.main=> (def system (new-system 8888))
#'usermanager.main/system
usermanager.main=> (alter-var-root #'system component/start)
Exception: [SQLITE_ERROR] SQL error or missing database (table department already exists)
Looks like the database is already setup?
2020-05-27 14:58:58.321:INFO::main: Logging initialized @128671ms to org.eclipse.jetty.util.log.StdErrLog
2020-05-27 14:58:58.398:INFO:oejs.Server:main: jetty-9.4.12.v20180830; built: 2018-08-30T13:59:14.071Z; git: 27208684755d94a92186989f695db2d7b21ebc51; jvm 14+36-1461
2020-05-27 14:58:58.460:INFO:oejs.AbstractConnector:main: Started ServerConnector@4d12e75d{HTTP/1.1,[http/1.1]}{0.0.0.0:8888}
2020-05-27 14:58:58.461:INFO:oejs.Server:main: Started @128811ms
#<SystemMap>
usermanager.main=>
require
then in-ns
. require
loads the code. in-ns
moves you into a namespace (that should already exist via require
)
@seancorfield, unfortinately, I can only work on clojure 6 AM to 8 AM EST. My day job, which is 8 to 6ish, is embedded C++, I am working on IoT low power instrument, but glancing at your comment, I think I should be able to get it.
I'm on Pacific time so your Clojure window is in the middle of my night š but if you ever find time to work on Clojure after work I'll likely be around. I used to do a lot of C++ in the '90s (I was on X3J16, the ANSI C++ Committee, for eight years back then).
@seancorfield, wow, was your jorney from C++ hard? by the way, I look at your dot files almost every day, I try to avoid layers of complexity and that is why I am trying to simply use clj.
I was lucky -- I'd done some Lisp and ML and other FP at university back in the '80s, then my professional arc was primarily COBOL, assembler, C, C++, Java, <more JVM stuff), Scala, Clojure -- so I've transitioned back to FP. If you've only/mostly done OOP (C++/Java), then it can be really hard to unlearn those "bad" habits in order to become fluent/idiomatic in Clojure.
Yes, the brain has to twist, but it seems like there are fewer but more applicable design patterns. Also, starting the server in REPL with the REPL prompt available is not as obvious. So I did a pull request to add the instructions to README.md
, if it makes sense, maybe you can approve it.
Actually, looking through the code, the instructions are there, but for noob like me, having staring point identified in README.md
will be helpful.
@seancorfield I have been studying the usermanager example, so using it as is, and starting it in REPL, will not reflect code changes upon reload, correct? How do you get the code to live reload? Is it possible to run command sequence to start the server in such a way that it will live reload?
@U012GN57FJ9 It does support live code changes. No reload required. You start it in the REPL, per the (updated) README / docstring that you saw, then you just eval changes into that REPL.
Should you be able to make the updates and hit reload on the browser and see the change? Or do I need to do something in the REPL?
You just eval the function and click to the next page in the browser (or reload if you want to see the change on the same page). I've tested this -- it does work.
It works because the example code uses #'
for all the function references (for things that might change) rather than plain symbol names.
OK, yes, it works, I was doing something wrong, now it is working perfect.
using deps.edn I am including a dependency that is :aot
-ing one of their dependencies. Is it possible to create an exclusion via deps.edn for the dependency that is being :aot-'d ?
Is that aotād into the first dependencyās artifact? If so, then no (doing this in an artifact is imo always a problem)
š Hey ya'll. I'm newbie to Clojure but have a background in Scala, Haskell, and Elixir. I've just joined a Clojure shop as an SRE and would appreciate being directed towards any channels that, at least occasionally, talk about things like observability, monitoring and logging. I was able to get my first Ring server running this weekend with tracing and monitoring in just a few hours, which was exciting. Looking forward to my next step in the FP journey!

@goedelsoup There's #observability -- it's not very active but has had a few interesting discussions
suppose I have
{{:foo 5} 4 {:something-else 6} 76 {:something-else2 6} 78 }
basically pairs of maps and numbers. How can I map them or iterate through them?user=> (doc partition)
-------------------------
clojure.core/partition
([n coll] [n step coll] [n step pad coll])
Returns a lazy sequence of lists of n items each, at offsets step
apart. If step is not supplied, defaults to n, i.e. the partitions
do not overlap. If a pad collection is supplied, use its elements as
necessary to complete last partition upto n items. In case there are
not enough padding elements, return a partition with less than n items.
(map prn my-coll)
this will print out each. but map
will call seq on its argument and a seq of a map is a collection of key value pairs
I've always wondered why the 2-arity of the reducing function associated with a map-transducer has the signature [result input & inputs]
(https://github.com/clojure/clojure/blob/clojure-1.10.1/src/clj/clojure/core.clj#L2743)
I understand that the arities of map
that take multiple collections
apply the lambda to the tuples formed by zipping the collection
arguments together.
That said, I don't understand how one could leverage the variadic in the signature linked above. Is there a transducing context that allows for that?
Is there a way to combine the contains? and every? fxns? I'm trying to check if a map contains all 3 keys with none unaccounted for
@sova I'd be inclined to use something like
(= #{:a :b :c} (set (keys (select-keys m [:a :b :c]))))
as a function (defn all-present? [keyset m] (assert (set? keyset)) (= keyset (set (keys (select-keys m keyset)))))
or what about (every-pred :a :b :c)
works for callable keys, not for strings etc.
(every? m [:a :b "c" 1])
works but only for non-nil vals
(and for callable maps, but all clojure native maps are callable)
(every? #(contains? m %) [:a :b :c])
also seems reasonable
yeah, I'd go for that if nil/false vals are OK, m as the predicate otherwise
what does #(contains? m %)
do there? i guess it get what it does but the high level #()
is unclear, as is the variable expansion with %
same as this (fn [x] (contains? m x))
it's an anonymous function where the first argument gets bound to %
#() is a reader macro
user=> '#(contains? m %)
(fn* [p1__2#] (contains? m p1__2#))
the cool thing with reader macros is you can use ' to expand the macro but not run the code
user=> '@foo
(clojure.core/deref foo)
user=> '#_ x y
y
user=> '#'foo
(var foo)
user=> (pprint '`(x ~y ~@(g z)))
(clojure.core/seq
(clojure.core/concat
(clojure.core/list 'user/x)
(clojure.core/list y)
(g z)))
nil
If middleware is done as a "pre-request handling" operations, would there be an equivalent response middle?
ring is functions (granted that abstraction is leaky), and functions don't have a "do stuff after they return in someway" hook
I'd like to add a cookie on every request but I want to avoid having to add it on a per-resource basis
and by wrap all your routes I mean, take all your routes, bundle them together as a single function (which is what the compojure routes function does) and then wrap that function in some middleware
some routing libraries provide features that only work if they can inspect the routes with actually running them (which compojure cannot do) often with that they do force ring middleware to be added at the leaves
Thats what I did originally but the cookie wasn't being set. Looking at the documentation
To set a cookie, you add aĀ :cookiesĀ key to the response map
So I tried adding the cookie explicitly in the response and thats when it worked. So I thought I'd have to do it at that level as opposed to inside the middleware functions
you are probably are using some middleware that is handling the cookies for you by looking for the :cookies
key
the :cookie key works because of someother middleware, so as long as your middleware runs adds that key before that middleware does your are fine
(defn example-middleware [handler]
(fn [request]
(let [modified-request (assoc request :foo 42)
_ (println "happens before")
response (handler modified-request)
_ (println "happens after")
modified-response (assoc-in response [:headers "Foo"] "42")]
modified-response)))
Figured out how to go about it with your example, thanks! Took a while to understand what you were getting at lol

middleware is legitimately tricky, but itās pretty handy once you grok it. thereās also some deep similarities between middleware and transducers
middleware does have a sense of ābeforeā and āafterā, but it can also depend on the order the middleware functions are setup
(def external-app (-> (apply routes [external-home-routes
external-status-routes
self-serve-routes
saml-routes
(route/not-found "Not found")])
(wrap-auth)
(wrap-cookies)
(wrap-resource "public")
(wrap-base-url)
(wrap-json-response)
(wrap-json-body {:keywords? true})
(wrap-multipart-params)
(wrap-params)
(wrap-content-type)
(wrap-cors :access-control-allow-origin (cors-allowed-origins)
:access-control-allow-methods [:get :put :post :delete]
:access-control-expose-headers ["Location"])))