Thanks for the information and the links. I'm working my way through a course on building APIs using Reitit, and once I get past whatever's blocking me right now, I'll try to build a sample API with this pattern in mind.
One thing you can do is expose a namespace that requires all of the defmethod-containing namespaces and make it so users require that
Right now it sounds like they are requiring the namespace with the defmulti- maybe stick the defmulti somewhere else, then in this top level NS require all of the namespaces that extend the defmulti
it seems like there is an implicit dependency between the code calling the multi method and the namespace implementing some corresponding defmethod. it seems like the "right" answer is to make the implicit dependency an explicit dependency (ie. make it so there's no way to call the the multi-method with args you expect it to handle without requiring the namespace that provides the implementation for those args). it's hard to offer more specific advice without knowing a little more about the use case.
@sova this will have the same problem, I believe
Yikes! I just checked and on my MacOS machine, /opt/intel (where MKL is installed) is around 3GB. Perhaps 22GB is required during installation but not after the installation is complete?
Hi. Can someone please tell me how to stop a live webpage or whatever it's called?
I'm trying to learn how to make a webapp and from advice here I turned to Luminus.
I created a Luminus project using the simple line on the Luminus front page (`lein new luminus myproject`), but after that generated a huge, complicated project folder I figured I need more a guide, so I want to follow through their 'Your First Application' page instead ( https://luminusweb.com/docs/guestbook.html ). That required creating a new project (with lein new luminus guestbook +h2 +immutant
), but that threw the error (among others) "Address already in use: bind". I think the problem is the first project is still 'live'.
Just running lein new
should not start a web server. What did you run after that?
Unless you are working through the Web Development with Clojure book that is based on Luminus, I would avoid Luminus until you understand the basics of web development in Clojure. Luminus is very complicated -- as you've discovered -- and with +h2 +immutant
you are just adding even more pieces that you will need to understand.
Start with just Ring. Build a minimal web server that says Hello, World!
when you visit it in a browser. Add Compojure so you can define some routes for GET/POST requests. Add Selmer so you can display HTML pages from Django-like templates, and render data into those pages.
See https://github.com/seancorfield/usermanager-example if you want something that is Ring + Compojure + Selmer + Component + next.jdbc which is the next step from the above. The README there also links to that same example but using Reitit and Integrant instead of Compojure and Component. Reading both of those will give you a good sense of how a basic web app can be written and for some different options for route definition and initialization/lifecycle management.
From the Luminus front page:
$ lein run
Started server on port 3000
...and when I point my browser to http://localhost:3000/ I see a local webpage that is the template project.
I just want to terminate that...so that the NEW project can start a new one (webserver process?)
You stop it the same way you stop any process running at the command-line.
@factorhengineering If it's Mac or Linux, use control-c. If it's Windows, use control-z.
I have a lot of cmd windows open. Guess I'll have to comb through them all and find the one for that project.
Found it. [Ctrl]+[c] worked to kill it. Successfully ran the 2nd project. Thanks.
@seancorfield I got conflicting advice on how to start. I took the Luminus suggestion because I had come across about 50 proper names for bits of tooling/libraries/frameworks/unknowns and Luminus seemed like it included a lot.
Combing through and trying to learn and make sense of a big complicated pre-made project (template?) might not be the best way, but after days and days and days spent just trying to figure out how to set myself up to finally actually start coding in ClojureScript again (I did the quick start guide and completed a very simple webpage with cljs a year or two ago) for something like an actual webapp, I'm just exhausted trying to figure out what each of those 50 bits do and how to put them together.
If things were clearer I would try more of a piecemeal approach, as you suggest, but for now I'm out of patience with that and have to try bending an all-singing-all-dancing sample webapp to my design instead.
Yeah, web dev in Clojure is "simple" but not "easy".
I mean, unless you insist going with Luminus at this stage is an absolutely terrible idea....
At work, as we've built each new web app, we've refactored parts of previous apps into libraries that allow us to assemble things a bit faster, but we still essentially start with Ring + Component + a routing library (mostly Compojure but we use Bidi on one) + Selmer for HTML templates + next.jdbc for DB access...
I think if you're going to persist with Luminus, and especially if you want to get into ClojureScript as well, you would definitely be doing yourself a favor to buy the book https://pragprog.com/titles/dswdcloj3/web-development-with-clojure-third-edition/ -- the 3rd ed is still in beta but it's mostly finished at this point (I bought one of the early betas and you get updates as they are released).
'Component' is a thing? That makes 51 I've come across.
And for just $26 for the ebooks, that's a bargain.
Component is the oldest and probably most widely used lib for initialization/lifecycle management.
...and I'm just running into the name now, after Leiningen, Shadow-cljs, deps.edn, tools.deps, boot, datomic, datascript, postgres, hiccup, quill, play-cljc, tailwindcss, nvm, bulma css, clj-kondo, reagent, om, om-next, rum, graal, truffle, cdk-clj, oz, re-frame, petrol, keechma, nativescript, fulcro, crux, hoplon, chord, couchbd, rest, spec, netty, aleph, pedestal, lacinia, hx, hxframe, reitit, http-kit, compojure, bidi, ring, pathom, clj cli tools, chestnut, luminus, h2, immutant, analemma, monet...and that's just writing down the ones I think there's a chance I might want at some point!
So I just ran:
clojure -X:new :template luminus :name guestbook.core :args '["+h2" "+immutant"]'
(which is the Clojure CLI equivalent of your lein new ...
command)
and then dropped into the new project and did lein run
... and it pretty much downloaded the entire internet before it started up an app on port 3000 π (edited to say port 3000 -- I just noticed it is nREPL that is started on port 7000... it's been so long since I started a process that used nREPL!)forgot figwheel and figwheel-main!
in my list
Ha ha yes. I'm on a 4k screen at 125% display element size and couldn't believe the downloads didn't fit in a full vertical strip cmd window.
I'm also looking everywhere in that project folder to try to find the html (or hiccup) file for the webpage it's showing me, and I can't find it. Crazy.
HTML pages are in the resources
folder
seanc@DESKTOP-30ICA76:~/clojure/guestbook.core$ tree resources/
resources/
βββ docs
βΒ Β βββ docs.md
βββ html
βΒ Β βββ about.html
βΒ Β βββ base.html
βΒ Β βββ error.html
βΒ Β βββ home.html
I did find that there, but nothing with all the text on the page served up.
By the way, what does your page read?
The resources
folder also has the CSS etc (under public
) and the SQL file used by the migrations library...
Congratulations, your Luminus site is ready!
This page will help guide you through the first steps of building your site.
Why are you seeing this page?
The home-routes handler in the guestbook.core.routes.home namespace defines the route that invokes the home-page function whenever an HTTP request is made to the / URI using the GET method.
is what I see in the browser.Apparently that's from the docs/docs.md
file...
OK. Same as mine. Good. I thought it would look different than the vanilla project (not guestbook with h2 etc).
Which in turn comes from this function in guestbook.routes.home
:
(defn home-page [request]
(layout/render request "home.html" {:docs (-> "docs/docs.md" io/resource slurp)}))
I don't see where that html text is coming from though! I've looked at all the /src clj files and all the html files in the folder you mentioned.
home.html
has
{% block content %}
<div class="content">
{{docs|markdown}}
</div>
{% endblock %}
and "extends" the base.html
template
I did notice " <div class="content"> {{docs|markdown}} </div>" in one of the .html files, but had no idea where to look from there.
base.html
is the "wrapper" with all the <html> <head> ... </head> <body> .. </body> </html>
stuff and it contains:
<section class="section">
<div class="container">
{% block content %}
{% endblock %}
</div>
</section>
that's how the content from home.html
is pulled in.
This is leveraging Selmer to have a common wrapper page and to override just certain segments of it in "derived" pages.
How does {docs|markdown}
or {% block content %}
refer to anything??
In Selmer {{var}}
renders whatever value is associated with the key :var
in the data (hash map) passed to the render
function.
and why on Earth would the html be in a .md file (which I just found)??
{{var|foo}}
applies the filter foo
to the value of var
before rendering it as a string.
So the markdown
filter takes Markdown as input and produces HTML as output.
It's so obfuscated. What's wrong with an actual html file, and what's wrong with just stating the path and filename of it?
("filter" in Selmer is really a transform -- it doesn't actually filter the input)
Yeah, this is exactly why I tell beginners not to use Luminus π
But seriously, beyond just being terrible for learning, why would even an advanced user want to use markdown that contains html?
I'm familiar with most of these libraries after years of using Clojure and even I have to hunt around in the source tree for a Luminus project to figure out what it's doing -- because it is using a bunch of libs I don't know and it wraps up the ones I do know in "unusual" code (i.e., stuff I haven't yet read).
...and isn't HICCUP the best practice anyway? The Clojure way for generating html?
I was looking forward to using that.
The markdown doesn't contain HTML. Markdown is a formatting style that can be rendered to HTML. Hiccup turns Clojure data structures into HTML. I find it horrible for collaboration -- I use Selmer so I can use HTML files with substitutions in so that my UI/UX folks can work on the same templates... they could not work with Hiccup.
We do also use Hiccup at work, but only for rendering XML that we need to send to a search engine.
OK most of the .md file might not be html, but it does contain some (`<a class="level-item button" href="https://luminusweb.com/docs/html_templating.html">learn more about HTML templating Β»</a>` and <p class="title is-5">Organizing the routes</p>
Sure. Markdown can contain HTML for finer control over formatting than raw markdown provides. That's "standard" with markdown.
The lightbulb brightens a bit more..
...from about 2% to 2.1%. lol
Some people prefer markdown to HTML when they can get away with it π
I've never used it. I just helps get bullets or something, is all I know. Seems like kind of a waste of time IMHO.
With that Luminus project example, you know you're in for a lot of learning when the top-level dependency list is:
:dependencies [[cheshire "5.10.0"]
[clojure.java-time "0.3.2"]
[com.h2database/h2 "1.4.200"]
[conman "0.9.1"]
[cprop "0.1.17"]
[expound "0.8.7"]
[funcool/struct "1.4.0"]
[luminus-immutant "0.2.5"]
[luminus-migrations "0.7.1"]
[luminus-transit "0.1.2"]
[markdown-clj "1.10.5"]
[metosin/muuntaja "0.6.7"]
[metosin/reitit "0.5.10"]
[metosin/ring-http-response "0.9.1"]
[mount "0.1.16"]
[nrepl "0.8.3"]
[org.clojure/clojure "1.10.1"]
[org.clojure/tools.cli "1.0.194"]
[org.clojure/tools.logging "1.1.0"]
[org.webjars.npm/bulma "0.9.1"]
[org.webjars.npm/material-icons "0.3.1"]
[org.webjars/webjars-locator "0.40"]
[org.webjars/webjars-locator-jboss-vfs "0.1.0"]
[ring-webjars "0.2.0"]
[ring/ring-core "1.8.2"]
[ring/ring-defaults "0.3.2"]
[selmer "1.12.31"]]
π(That's a fraction of what we have in our apps at work tho' -- where we have over 108K lines of Clojure across over three dozen subprojects that we build over a dozen apps from)
It seems like my choices are (a) go from scratch and deal with an endless amount of made-up-name tooling bits and do an epic walk through at least their documentation introduction (to try to figure out what they do and what is in competition with what), and try to cobble them together (and possibly do a whole lot of things manually that could be helped by some unknown tool in the meantime), or (b) start with a super-complicated example and embark in an epic search through the project structure (and maybe documentation on the dependencies once in a while) if I want to make a small change to make the thing look more like the webapp I want.
What a choice.
Have you heard much about chestnut? One of those many many cutesy tooling/library/framework/unknown names I came across, but supposed to maybe be some kind of all-singing starting points like Luminus.
...but maybe a bit simpler? I mean I don't see how it could be more complex!
I had heard of it but didn't know what it was. I just looked it up. It's another project template.
I have never used a project template -- other than the bare minimum lib
and app
-- in a decade of working with Clojure.
I don't do anything with ClojureScript. We looked at it in 2013/2014 and it was pretty horrible, especially in terms of tooling. That's improved a lot and we may try it again next year. I may build a smallish SPA with cljs and I'll start with re-frame and shadow-cljs and see how it goes.
Why shadow over leiningen (and I think figwheel/figwheel-main? it is in competition with (does the same things as) that too, yes?)?
or over deps.edn?
err...deps.edn + figwheel-main I guess
I haven't used Leiningen since 2015.
Similar question: Why re-frame over...(let me check my giant list, hoping I've correctly grouped things that are in competition with each other)...reagent, om-next, or rum?
I switched from Leiningen to Boot in 2015 and then to the Clojure CLI in 2018.
re-frame adds structure to reagent, in the same way that Redux adds structure to React.
Uh-oh...item #52 for my lest. Hadn't come across 'redux' yet. Sigh.
Back when I last did cljs, there was Om and Reagent (and Reagent was new). My team built an app with Om and then rebuilt it with Reagent and we liked Reagent better (and I contributed to it a bit back then). re-frame is newer and builds on top of Reagent.
It's like whack-a-mole with these tooling/etc names.
@factorhengineering is this different from the rest of the software ecosystem?
Redux is a JS framework or at least a structured way of working with React when you have a data store and you are managing events and changes, as I recall.
There is not a central planning committee here that is fumbling their planning ;)
Lots of fun and interesting personalities and history behind why all of these exist
My reading of re-frame is that it's basically "Redux" in a cljs context, built on Reagent, whereas Redux is built on React -- and Reagent is a cljs wrapper for React π
@factorhengineering remind me, what's your programming background before Clojure? I'm curious as to what sort of ecosystem you're used to elsewhere...
I just +1d two really helpful comments of yours above. I thought I had to choose between re-frame, reagent, om-next, and rum. Good to know re-frame subsumes reagent.
Also nice to hear your lein-to-boot-to-cljcli experience.
@factorhengineering still better than the energy bar situation here in Boulder! 100s of choices. (Didnβt mean my comment to be negative, I am smiling with you since of course youβre right that this is bewildering)
Why does Luminus only mention lein and boot then, btw?
It's so nice to be laughing with other people about this instead of crying that on hour 100 or so of my latest foray into cljs I still haven't written a single line of it.
Luminus predates the Clojure CLI and hasn't adapted to it yet.
I think many folks find a build setup (after much struggle with cljs for example), and then that becomes their personal project template for new work
I have harassed the maintainers of project I use to offer CLI support or I've sent them PRs. I haven't had much incentive to do that with Luminus π
The only thing that makes me sad about shadow-cljs is that it sort of expects node.js to be installed. And every time someone installs node.js, a kitten dies π
Maybe I'll start with figwheel-main instead since it supports the Clojure CLI and doesn't seem to require node.js?
(everything has changed since I last looked at cljs!)
What's wrong with node.js?
I did try to use shadow.cljs about 6 months ago, but that fizzled. So complicated.
Had a kind soul here link me to his personal walkthrough on setting up a simple thing, and further walk me through it, but I was just typing in set-up commands without them making sense. π
A-a-nd I just created yet another project without editing the previous one at all. Ha. I just decided to take chestnut for a spin, hoping it might split the different between from-scratch and uber-sample-project.
Ran lein new chestnut projectnam +re-frame
<-- That extra argument based on your hint, @seancorfield. The default is Reagent, but with the argument it can do re-frame instead.
It looks a bit simpler than Luminus. It only downloaded a quarter of the internet.
@sritchie09 Of course I have to poll you too... π What do you use? Do you deal with ClojureScript at all or only Clojure?
Hey the /src folder in a chestnut project is further divided into /clj /cljs and /cljc. Cool. I like the idea of cljc.
@factorhengineering I just tried figwheel-main:
seanc@DESKTOP-30ICA76:~/clojure$ clojure -X:new :template figwheel-main :name hello-world.core :args '["--reagent"]'
...
seanc@DESKTOP-30ICA76:~/clojure$ cd hello-world.core/
seanc@DESKTOP-30ICA76:~/clojure/hello-world.core$ clojure -M:fig:build
...
[Rebel readline] Type :repl/help for online help info
Opening URL <http://localhost:9500>
(browser opens at this point)
ClojureScript 1.10.773
cljs.user=> (js/alert "Am I connected?")
nil
(browser shows that alert)
I edited src/hello_world/core.cljs
per the comment in the browser and saved it
[Figwheel] Compiling build dev to "target/public/cljs-out/dev-main.js"
[Figwheel] Successfully compiled build dev to "target/public/cljs-out/dev-main.js" in 0.464 seconds.
[Figwheel] Outputting main file: target/public/cljs-out/dev-main-auto-testing.js
This text is printed from src/hello_world/core.cljs. Go ahead and edit it and see reloading in action.
(sure enough, I see new text in the browser immediately!)
cljs.user=> (require '[hello-world.core :refer [app-state]])
nil
cljs.user=> (swap! app-state update :text str " More text!")
{:text "New text! More text!"}
(see the text change in the browser in real time)
cljs.user=> (swap! app-state update :text str " More text!")
{:text "New text! More text! More text!"}
(browser updates to show new text!)
OK, this seems fun. I think I'll go down this path when I need to build a cljs app.Hmm, pity that by default the test runner uses the same port as running the app. Luckily adding
:ring-server-options {:port 9555}
to test.cljs.edn
fixes that (but it took me a bit of grepping to figure that out)@seancorfield Reading through your posts now...
About to give up for the night, but in the meantime, if you feel like taking a quick peek at chestnut and seeing whether you think it's (a) good and (b) good for a newbie, that would be much appreciated (as has been the whole discussion with you tonight).
By the way, I ran lein new chestnut +re-frame +http-kit +bidi +garden
(heard re-frame better than default reagent, heard http-kit better than default jetty, heard bidi better than default compojure, and garden for clj(s) css syntax)
Running the command in the readme.md
file it generates (
clojure
(go)
(cljs-repl)
) does not seem to work the way it says it should, though. Nothing to see on localhost:10555 (nor localhost:3449).@seancorfield @factorhengineering I am a fan of figwheel-main, esp. for browser-based React app itβs a no-brainer; after a lot of React experience (+ React Native) I eventually settled on managing my own state and doing direct React interop from Cljsβ¦ but for a first project something like Reagent might be easier
@factorhengineering I fully support @seancorfieldβs suggestion to go easy on the frameworks to start; just like @seancorfield said following whatβs described at https://github.com/seancorfield/usermanager-example should be enough to get you going
Have you tried shadow-cljs? How is it lacking compared to figwheel?
I also just ran lein new projectname fulcro
(before seeing your comment, @raspasov). It downloaded almost nothing (far less than chestnut and far, far less than luminus). The folder-and-file structure seems at least a bit less complex than chestnut's and luminus' as well. Would be interested in your opinion on that too, @seancorfield, if you feel like littering your computer with yet another project folder as I have many times tonight.
Fulcro is hard to get into, I have been coding in clojure&cljs since March, and have decided to rewrite my re-frame app in fulcro 10 days ago, struggling a lot right now. Unlike re-frame&reagent, where you can be productive after a ~day of reading their docs. It is a lot to take in even without having to learn the rest of the stack and the language itself.
Based on what I just tried this evening: shadow-cljs relies on node/npm/npx, figwheel does not -- that's a huge win for figwheel for me.
I see your suggestion, @raspasov, so I gather that the https://github.com/seancorfield/usermanager-example (and https://github.com/PrestanceDesign/usermanager-reitit-integrant-example) are even lighter starting points than all 3 of the 'frameworks' I've set up projects using (luminus, chestnut, fulcro)? I don't see a lein command for setting them up, though, so I would have to figure out how to start with them (just git commands I guess)...and now that I look further I see I would have to figure out how to install the 'clojure cli' too?
It is very easy to use js libs from shadow though, I think figwheel might have some troubles with that?
@factorhengineering both of those usermanager examples assume you're using the official Clojure CLI rather than Leiningen.
You could manually add a project.clj
file to them and use lein
if you want...
@posobin I winced at your comment "re-frame&reagent, where you can be productive after a ~day of reading their docs" (but to be fair to myself I'm not even set up to the point of being able to write any code yet, so who knows yet) but regardless you've successfully scared me off fulcro. Thanks for helping me whittle down the options.
@posobin Yeah, I assumed that was the "big difference" but I think I'd rather eschew JS libs for now...
(I find the whole JS ecosystem thoroughly unpalatable)
I don't necessarily want leiningen. I'm just familiar with it a bit, having seen it make it easy for me to make a bunch of projects with different frameworks appear on my computer tonight (and using it for the initial creation of the project folder for the simple webapp I made last time around).
Based on the last hour of playing around, I have to say that re-frame looks really nice! So I think when I'm ready to do cljs again, it'll be re-frame and figwheel-main at this point π
I might be wrong, but I have a feeling shadow-cljs can run without npm. If I remember correctly, that's how I ran it last year when doing cljs stuff. Sure, the user guide suggests using the npx thing, but you can install it as a jvm library and invoke it through lein / deps (see https://shadow-cljs.github.io/docs/UsersGuide.html#_library & https://shadow-cljs.github.io/docs/UsersGuide.html#deps-edn)
and none of that requires leiningen? Based on a couple of command line commands you pasted above it seems like lein commands can be substituted with just slightly more complicated clojure commands.
@factorhengineering my feeling about lein
and the Clojure CLI is that the CLI is officially supported, and officially documented on http://clojure.org and that means it'll be more and more popular over time so you might as well install and use it for projects that support it (or even require it).
reagent+re-frame are probably the most used options currently, so you're most likely to be able to get help with that. both figwheel-main and shadow cljs are well supported as well
I concur, a while ago I put together a very simple little show-and-tell using re-frame, reagent, reitit, next.jdbc - didn't take long at all, and I found it a pleasant experience.
@factorhengineering I don't use Leiningen -- unless I have to in order to help a beginner debug a problem.
@dharrigan I assume with figwheel that you run separate front end and back end REPLs / processes? (I haven't gotten that far with it yet)
I had a failed attempt at trying shadow-cljs earlier this year. The farther I got into the long usage guide the more the fog rolled in around me. Not totally discounting it, but it kind of makes me want to try something else this time.
Still...my main issue remains knowing what all the parts and options really are to begin with.
I got the impression that shadow-cljs was somewhat all-encompassing in that it would start both front end and back end pieces together?
Shadow sounded great. It would need a second stab at it by me though.
@lasse.maatta Ah, good to know. Thanks. So I may yet consider it at some point...
that's not how I use it. you can do that with either shadow-cljs or figwheel-main, but you don't have to. whatever ring support is there is just a convenience
Name #53 to add to my list: next.jdbc
#54: crux! π
crux is on my list already. π
Hi, yes, that is correct. I admit, I'm not really a "frontend" type of developer, so perhaps there are better ways. However, having separate repls worked very well for me to do a bit of learning.
It sounds nice and simple -- and I'm a big fan of "simple".
π
It in the spreadsheet column under 'other', i.e. among those I know the least about or think I am least likely to need. Who knows, though? π
@factorhengineering if you get around to next.jdbc
at some point, the #sql channel will be a good resource for you π
(if you want to do anything with an RDBMS/SQL database, you'll use next.jdbc
)
Really? How is it so late on my list then? Ha ha. The whack-a-mole game continues...
When you say in your...template(?) "This example assumes that you have the https://clojure.org/guides/deps_and_cli installed", is that really a separate installation?
To add to @seancorfield excellent example, I humbly present my own little take, which uses juxt clip
and reitit
for frontend and backend <https://github.com/dharrigan/startrek>
and <https://github.com/dharrigan/startrek-ui>
that's where you install it. it is not "separate" from Clojure, but it's separate from @seancorfield's template
although you can use Clojure without installing that, so in that sense it is "separate"
Yeah, what @euccastro said. http://clojure.org has the Getting Started guide, the "deps and CLI" guide, and the "deps and CLI" reference -- because the clj
/ clojure
commands are the official CLI from Cognitect.
Oh wait, I finally found the installation instructions. Powershelling now...
in case you haven't seen it, this is pretty crucial too: https://clojure.org/guides/repl/introduction
I mean...first have to figure out what I'm supposed to set my JAVA_HOME environment variable to....
why do you think you have to set that?
@factorhengineering here's your (long) list updated with the stuff crossed out that I think you can safely ignore to get started: Leiningen, Shadow-cljs, deps.edn, tools.deps, boot, datomic, datascript, postgres, hiccup, quill, play-cljc, tailwindcss, nvm, bulma css, clj-kondo, reagent, om, om-next, rum, graal, truffle, cdk-clj, oz, re-frame, petrol, keechma, nativescript, fulcro, crux, hoplon, chord, couchbd, rest, spec, netty, aleph, pedestal, lacinia, hx, hxframe, reitit, http-kit, compojure, bidi, ring, pathom, clj cli tools, chestnut, luminus, h2, immutant, analemma, monet -- plus I would add component, selmer, next.jdbc
"Make sure https://aka.ms/wmf5download (or later, include https://aka.ms/pscore6) and https://www.microsoft.com/net/download (or later) are installed. Also install Java 8+ and set JAVA_HOME in your environment variables. Then run:"
I thought you were on Mac/Linux? Install the Clojure CLI there. Don't try to deal with Powershell.
Oh no. Totally glossed over the .net thing. Ugh. Always so many hoops to jump through. Oh and of course my JAVA_HOME is already set, but it's to JDK 11 even though I jsut installed 8? Sigh.
I'm on Windows.
JDK 11 is fine. why do you want 8?
Even on my Microsoft Surface Laptop 3, I do not use Powershell. I do everything on Ubuntu via WSL2.
Unless I line up a bunch of new tasks and finally get Linux dual booting on this somewhat new-ish computer.
You do not need to dual boot
...or that. Find out more about what WSL is all about.
When you were showing your shell stuff above, you had a $
prompt so I assumed it was macOS or Linux π
off @seancorfield's list you can probably further cross out either Compojure or reitit, since both do routing
Is it like a VM, or can you actually shut down and restart and come back to things...like on a part of your disk space theretofore dedicated to WSL/Linux?
Yup, I was just leaving those as both useful options since reitit is data-focused and compojure isn't @euccastro
Oh that $ was just from me quoting the front page of the luminus website.
@factorhengineering I think in a cmd window or Powershell you can just type bash
and it will set up WSL2 for you, as long as your Windows 10 install is up to date?
BTW I have gathered that the following are in competition: pedestal, reitit (how do people pronounce that??), compojure, bidi (frontrunner AFACT), ataraxy, keechma
...and I have a bunch more names of things that might be 'routing libraries' too.
@factorhengineering as in route-it
Keechma is a "micro-framework for Reagent" so I wouldn't say it was a routing library.
Nor is Pedestal.
@ikitommi said "ray-tit", but it may have been tongue-in-cheek?
I'm sure I read the git page for something calling itself a routing library referring to those as also routing libraries. Ha.
reitit, compojure, and bidi are comparable. I would recommend reitit or compojure.
Finnish pronouciation?
Haha after I had kind of settled on bidi (through descriptions alone).
@factorhengineering it's probably best to "just pick one" and not worry about alternatives -- pick the most popular one and move on.
Nope, that's the proper Finnish pronunciation of it
Ah-ha!
π
From the reitit git page: "Existing Clojure(Script) routing libs, especially to https://github.com/weavejester/ataraxy, https://github.com/funcool/bide, https://github.com/juxt/bidi, https://github.com/ikitommi/calfpath, https://github.com/weavejester/compojure, https://keechma.com/ and https://github.com/pedestal/pedestal/tree/master/route."
Actual Calfpath link is this: https://github.com/kumarshantanu/calfpath and a comprehensive coverage of routing libraries here: https://purelyfunctional.tv/mini-guide/clojure-routers/
so confusing.
That's being very generous...
some of those do routing + more
How do I know what's the most popular?
Compojure is far and away the most popular.
You can look at stars/watches/forks on github or downloads on http://clojars.org
OK, I've heard of stars. ...but doesn't that leave out the time element? i.e. favour things that are or were popular at any point in time, not specifically now?
do stars 'fade'?
compojure has 8.something million downloads on http://clojars.org, bidi has 900K, reitit has 400K
my feeling is that it's losing popularity to reitit, in part because the latter is data-based as opposed to macro-based
but it's just an unsubstantiated impression
Is there a d-star/d-time derivative stat? lol
reitit will also work in the browser side if you want that
if you are unsure you could start with manual routing. for simple websites that should work well enough, and it might help you understand what these libraries are doing
I might try to hack something---anything--together by twiddling with the chestnut project until I have the patience to figure out WSL (or install .net and fix what version of java my java_home variable points at).
I'm really foggy on what routing even is.
take a ring request, decide what function will handle it
The current projects I have in mind are both stand-alone.
FHE, if it's any consolation I remember going through the same kind of "there's too many libraries in this ecosystem (and some of them are obsolete!)" hassle when first learning enterprise java (and later javascript) years ago
ring request?
Also, do I need 'ring'? Another name on my list.
a ring request being a Clojure map with information about a web request, most importantly the path and any headers
@factorhengineering Ring is fundamental to web apps in Clojure. Pretty much everything else is built on Ring.
This is why I said: start with a bare bones app with just Ring and nothing else.
Built-in, or separate install (or dependency to add)?
When my Clojure Provo talk is put online -- after my London talk -- you'll be able to see what it looks like to start from a minimal app and add just Ring and build a simple web app. Although I'm sure others have done such videos online.
Sorry. I don't remember you saying that. I've heard a lot of things lately. It sounds like your usermanager template is close to that, though.
Sure, usermanager = Ring + Compojure + Selmer + Component + next.jdbc
It mentions just https://github.com/stuartsierra/component, https://github.com/ring-clojure/ring, https://github.com/weavejester/compojure, and https://github.com/yogthos/Selmer. I kind of know what selmer is (from luminus) and ring (now). Not sure about the other 2.
...or...3? next.jdbc isn't mentioned on that list.
https://github.com/seancorfield/usermanager-example/blob/develop/deps.edn -- it use SQLite for the actual DB (but it easily could be h2 or postgres) and it does depend on http-kit but that is totally optional (it's really just to show how interchangeable jetty and http-kit are).
Oh there it is, mentioned later. That's to do with the database for the app?
Yes, next.jdbc
is the Clojure JDBC wrapper.
(it supersedes org.clojure/clojure.java.jdbc
which I used to maintain)
Is there a simple way to describe what component and compojure do?
@factorhengineering you didn't answer my earlier question about your programming background? what languages are you used to?
Component is a library to help you manage the lifecycle (start/stop) of dependencies in your app (such as database connection pools, caches, web servers, etc).
Compojure is a routing library -- it maps URLs to functions in your code.
I worked on an Android app in Java a long time ago. I've done other Java too, but that doesn't mean I'm heavy into OOP.
I've done a bit of Python.
I've done some other things.
component manages the lifecycle of stateful things like web servers. in his presentation about this stuff @seancorfield just started the server manually by calling run-jetty. so I'm not sure you need it to get started https://ring-clojure.github.io/ring/ring.adapter.jetty.html#var-run-jetty
html, css, a bit of js, turbopascal LOL
ring is like Python's WSGI
OK, just asking so we can try to relate some of this Clojure stuff back to other stuff you know... but it sounds like you're pretty much a beginner across all languages really, so maybe there aren't going to be good reference points for you?
I don't recognize 'WSGI', if that confirms my polyglot beginner status. Ha.
OK, my battery is at 12% and my G&T is empty so I'm off to bed (got to be up early to go walking and get my five miles in before work!). Will no doubt chat more with you tomorrow π
I've messed around a bit with a lot of stuff, like regex and perl, and I've watch about 40 videos on clojure and clojurescript. I feel like I know more about the high-level language design things then how to just actually get going. Though I do have a clojure webapp I made that I use at work a fair amount.
It's a weird place to be. Motivated but paralyzed. Will try again soon. If not tomorrow then probably on the 1st at the latest.
Talk to you again soon. Goodnight!
@factorhengineering here's a minimal example of a working web application, with manual/no routing: https://github.com/euccastro/minimal-web
it just echoes back the ring request generated when you visit http://localhost:3000/echo, or a 404 not found if you visit anything else
once you understand that fully we can talk about the next step, which would maybe be to add a routing library
it does use deps.edn though, so it requires the Clojure CLI installed
(or maybe the next step is to add hiccup or selmer so you don't need to build the HTML by hand; whatever hurts the most π )
there are one or two important things to understand in that example, though, like the use of #'http-handler
for REPL-friendliness, and the use of a rich comment block to show example usage
I have written below code
(defn count-a-with-regex [body]
(let [regex (re-pattern var-regex)]
(map (fn [input]
(println "input -- " (type input ) )
(dbg (count (re-find regex input)))) (str body))))
and calling using (count-a-with-regex " Hello world hi world")
I am passing string but getting converting to java.lang.CharSequence
why my string is converting to charseq?
you can test in repl
use re-seq
if you want to count occurrences of the regex in the string
re-find gives you a single occurrence. iterating over that (i.e., a string) gives you a sequence of characters
if you want to count the characters of a singleoccurrence, re-find
is fine
Has anyone encountered this issue where code (tests) runs perfectly fine in the repl, even in the case of a fresh repl
but once you do lein cloverage
it throws a java.lang.IllegalArgumentException: no JSON input found
when that is an impossible path to execute (I even have a try catch block :x
Am I right to understand that this is the compiler's static analysis that is executing all code regardless of whether it is a possible path of execution or not?
Context: https://github.com/zero-one-group/fxl/pull/16/checks?check_run_id=1625450943
@euccastro re-seq returned ([${hello} hello] [${hi} hi] )
how can i fetch only ${hello} and ${hi}
@popeyepwr what is your regex? if it doesn't have groups you should just get the string matches:
(re-seq #"\w+" "one two three")
;; => ("one" "two" "three")
anyway, one way to get only the ${hello} and ${hi} out of your result would be (map first (re-seq ,,,))
Thanks @euccastro, I know it may be basic question... I am still practising clojure
np @popeyepwr, this is the channel for those π
(ns clojure-sandbox.core)
(def mylist
({:a 1 :b 2 :c 3}
{:a 1 :b 5 :c 6}
{:a 7 :b 8 :c 12}
{:a 10 :b 11 :c 12}))
println mylist
Gives me: Unable to resolve symbol: mylist in this context
When trying to compile (alt+enter) in vscode.. The same code ran fine yesterday.. I'm assuming "something" was cached, so this appearently now invalid code wasn't invalid yesterday π
Now I just removed a (def foo...) that was in the file - so it only contains the above - and now it fails with: "Unbound: #'clojure-sandbox.core/mylist"]
Any tips as to whats up? I'm really not feeling helped with that error πYour code isn't valid. Try putting a ' before the bracket for mylist
(def mylist
'({:a 1 :b 2 :c 3}
{:a 1 :b 5 :c 6}
{:a 7 :b 8 :c 12}
{:a 10 :b 11 :c 12}))
(println mylist)
You should have got an error when you tried to compile what you pasted though, I think.
I ran it yesterday and it returned the changed results as it should (all b's had the same content as c in that same map).. Today I opened up vscode and alt+enter and it broke..
thats really frustrating π
With the ' in front of the list - it runs and ofcourse returns nothing.. Whats wrong with the above ?
it works as a vector
So, without the ' in front of the list. It thinks that its a function call. You CAN call a map as a function, and pass it a key as the argument and get the value back for that key. However in your case it thinks you are calling it with 3 arguments. There isn't a map as a function with arity of 3 arguments. So it errors. > I ran it yesterday and it returned the changed results as it should (all b's had the same content as c in that same map).. Today I opened up vscode and alt+enter and it broke.. Do you have more code that you haven't shown?
(changing () to [] around the maps)
e.g.
({:a 5 :b 6 :c 7} :a)
;=> 5
({:a 5 :b 6 :c 7} :z :not-found)
;=> :not-found
no - its just a project created by: lein new clojure-sandbox
Putting the ' in front of the list quotes it, you are saying it isn't a function call, its a list.
(def mylist
[{:a 1 :b 2 :c 3}
{:a 1 :b 5 :c 6}
{:a 7 :b 8 :c 12}
{:a 10 :b 11 :c 12}
])
(map (fn [m] (assoc m :b (m :c))) mylist)
Worksso doing '({:a ... should make it a list ?
repl must somehow be running "parts of the old" or something yesterday
If you change the code you will have to resend it to the REPL
alt+enter doesn't do that ?
I don't know VSCode sorry, so I don't know what alt-enter does?
"evaluate top level form(defun)"
I was told to run that yesterday π
(def mylist
'({:a 1 :b 2 :c 3}
{:a 1 :b 5 :c 6}
{:a 7 :b 8 :c 12}
{:a 10 :b 11 :c 12}))
=> #'stuarts.2020day16/mylist
(map (fn [m] (assoc m :b (m :c))) mylist)
=> ({:a 1, :b 3, :c 3} {:a 1, :b 6, :c 6} {:a 7, :b 12, :c 12} {:a 10, :b 12, :c 12})
(def mylist
[{:a 1 :b 2 :c 3}
{:a 1 :b 5 :c 6}
{:a 7 :b 8 :c 12}
{:a 10 :b 11 :c 12}])
=> #'stuarts.2020day16/mylist
(map (fn [m] (assoc m :b (m :c))) mylist)
=> ({:a 1, :b 3, :c 3} {:a 1, :b 6, :c 6} {:a 7, :b 12, :c 12} {:a 10, :b 12, :c 12})
But yes, putting the ' in front of the list to quote it, will work. But I think generally you probably want a vector over a list.Thank you
Calva will use the Clojure REPL to evaluate the form. There is no extra magic there, so something must have been different with the code yesterday, if it compiled w/o error.
It ran with alt+enter and gave the expected output. I then just opened it today - and it failed compiling.. Sounds to me like some sort of caching of functions going on :(
Calva isnβt caching anything. You could have evaluated some working version of mylist
, though. That would make (println mylist)
βworkβ. And that working definition would be gone today, if you have restarted the REPL. This is a quite common problem when getting used to Clojure. I still trip on it at times, for sure.
Hi, I'm trying to get start my first full-stack clj web app. I've followed this guide that combines heroku deployment and datahike for the backend, and was able to generate a web app hosted on heroku: https://nextjournal.com/kommen/datahike-heroku-datalog-clojure-web-app. now I need to figure out how to 1) connect a repl to it, and 2) include figwheel/reagent to the stack for cljs. my app so far is on github: https://github.com/jollyblondgiant/datahike-heroku and attempting to connect to repl by calling heroku run lein repl
as described in the heroku/clj guide https://devcenter.heroku.com/articles/getting-started-with-clojure#start-a-repl-on-a-dyno results in an error that "project.clj" doesn't exist.
TL;DR I'm trying to start a full stack web app and have some questions:
1. what is your preferred workflow to start a mobile/web app with datalog and reagent? are there better options? what are they and how do I start them up?
2. what is missing from my app as it is that I can't start a repl?
@andy482 Heroku run will spin up a new container, using the image build during deployment. Not sure why you want to connect a repl to a copy of the app. Do you need a full stack app? There is more scalability in having a backend API and separate front-end apps. Back end and front end have different loads and resources, very inefficient to scale them as one monolithic app
I'm working on day 16 of advent of code, I've arrived at this data structure.
([0 "row"] [1 "class"] [1 "row"] [2 "class"] [2 "row"] [2 "seat"])
Is their an easy way to transform that into this:
[[0 "row"] [1 "class" "row"] [2 "class" "row" "seat"]]
Or should I look at changing the function that creates the initial structure to better collect the results?I use list comprehension to get those initial results, maybe I can change this?
(defn get-satisfied-rules [rules ticket-items]
(for [rule rules
ticket ticket-items]
(if (satisfies-rule? rule ticket)
[(first ticket) (first rule)])))
Can I collect the results into groups in the for ?(group-by first)
looks like it almost gets me there
{1 [[1 "class"] [1 "row"]], 2 [[2 "class"] [2 "row"] [2 "seat"]], 0 [[0 "row"]]}
Is it possible to use heroku run
to invoke a tools.deps alias? You could add + deploy an alias with nrepl (or whaterever) as an extra dependency
what's your preferred workflow for setting up such a system?
Got it!
(let [data [[0 "row"] [1 "class"] [1 "row"] [2 "class"] [2 "row"] [2 "seat"]]]
(reduce (fn [acc [i rule]]
(update acc i conj rule)) {} data))
;=> {0 ("row"), 1 ("row" "class"), 2 ("seat" "row" "class")}
Is their a better way?to your question-- I want to connect to a repl to start adding test data to my app.
if you replace conj
with (fnil conj [])
you'll get a vector instead of a list
it might be, but I couldn't tell you how as I am pretty nooby still.
oh cool! thanks!
aaah, so my way by saying (update acc i conj rule)
, if the entry doesnt exist in the map it passes nil
to conj and
(conj nil 2)
;=> (2)
but fnil is saying if the second argument is nil to replace the nil with [].neat!
well, first argument, but yes
yes, sorry first argument!
fnil is quite handy
(ins)user=> ((fnil + 1 2) 2 nil)
4
(ins)user=> ((fnil + 1 2) nil 2)
3
thats like creating a function with default arguments!
This is a sample alias you could add to your deps.edn:
:nrepl {:extra-deps {nrepl/nrepl {:mvn/version "RELEASE"}}
:main-opts ["-m" "nrepl.cmdline"]}
then, after itβs deployed, you could try running it with:
heroku run clojure -M:nrepl
then you should see its connection info pop upif you have the DB locally in your dyno you will lose it whenever you update your app
you need an external DB, at which point you should be able to connect to it from your dev machine
oh wait, IIUC you're using a Heroku postgresql backend, right? that'll work, but you should figure out how to connect to that [P.S.: I meant to the postgres DB, not to the Heroku app] from a REPL in your own dev computer. you should be able to
lol that's why I came here; thanks though
this gets me a repl!! thanks so much! I'm going to make sure there's a note that you helped get past this spot. is "nick from clojurians-slack" fine for credit?
Nice! Glad it worked out. Since my first name isnβt all that unique I usually use my GH username: nnichols
IIUC you should be able to use the very code you're using in production Heroku, just find the environment variable(s) you use to access Postgres here: https://devcenter.heroku.com/articles/config-vars
if you really want to connect to the Heroku app itself this might work: https://devcenter.heroku.com/articles/debugging-clojure
but I've worked with Clojure projects deployed to Heroku for a while and I've never found the need to do that
what's your preferred stack/workflow when starting a new app? I'm embarking on my first and could use advice. Thanks!
@andy482 this is the basics of my workflow with Heroku https://practicalli.github.io/clojure-webapps/projects/banking-on-clojure/
holy cow thanks
For test data, I would use a test database provisioned against a test app.
Still lots to add, feel free to ask questions...
I will be updating the Clojure specs as I got a bit carried away with the design
Can I do clojure development on Windows or can I better use linux ?
@roelof You can but generally macOS and Linux are better supported by tooling and libraries.
I do a lot of Clojure work on a Windows laptop -- but I run all of the Clojure stuff on Ubuntu via WSL2. I use VS Code on Windows, with the Remote-WSL2 extension which is pretty slick.
(Windows has always been a second-class citizen in the Clojure world -- because most Clojure devs who work on tooling and library use macOS or Linux)
oke, that is what I do also. Use wsl2
For non-WSL Windows use, I've been using deps.clj instead of the official Clojure CLI.
I think the combination of VS Code on Windows and running Clojure stuff on WSL2 is really solid. I run VcXsrv (Xlaunch) so that I can run GUI apps from the Linux side (Reveal, mostly, but sometimes also Google Chrome).
@seancorfield and then as extension use calva
I use Clover -- which is a version of Chlorine, ported from Atom to VS Code -- and I use a plain Socket REPL instead of nREPL.
I then have to figure out how I can easily surround or replace a parentheses
Hmm, I thought Calva included paredit and/or parinfer which handled that sort of thing? You could ask in #calva (or #vscode for general VS Code Qs).
Yeah, Calva does default to Paredit on, I believe. They have nice visual docs on the default commands. https://calva.io/paredit/
thanks all, GN