This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-03-06
Channels
- # adventofcode (2)
- # announcements (5)
- # architecture (4)
- # babashka (35)
- # beginners (28)
- # calva (4)
- # cider (9)
- # clerk (30)
- # clj-kondo (11)
- # clojure (58)
- # clojure-conj (3)
- # clojure-europe (71)
- # clojure-gamedev (2)
- # clojure-nl (3)
- # clojure-uk (2)
- # clojurescript (49)
- # conjure (2)
- # cursive (2)
- # emacs (4)
- # fulcro (1)
- # honeysql (2)
- # hyperfiddle (10)
- # jobs (2)
- # jobs-discuss (18)
- # leiningen (9)
- # membrane (14)
- # missionary (1)
- # off-topic (27)
- # pedestal (1)
- # polylith (5)
- # reagent (12)
- # releases (2)
- # remote-jobs (3)
- # shadow-cljs (83)
- # sql (5)
- # squint (13)
- # tools-build (13)
I am having difficulty how to structure a configurable values in a project suppose that initially I have a top-level def that is used inside several defn like this
(def port 4242)
(defn swap-body! []
(str "using the value " port))
(defn -main [& _] #_swap-body!-used-here)
and the later in the development, I decided to make this port
value configurable through -main
args, and to make that happen, I only know these options:
• make the port atom
• add parameter port to swap-body!
• define swap-body!
inside the -main
body like this
(defn -main [port]
(let [swap-body! (fn [] (str "using the value " port))]
#_swap-body!-used-here))
but I feel like all of these options are awkward. I have more things that I want to be configurable at the initialization and not just limited to static values (like predicates fn for example). I feel like the option 1 will be the least obstrusive change if I make one big atom containing all the config, but I was not so sure so currently I am using option 3 since I only need to move the definition, Does anyone have advice?it's usually option 1 or option 2. Option 1 gives you ease of use, option 2 give you more control (it allows you spawning several servers for instance). You can check out https://github.com/grammarly/omniconf if you go with option 1
there is also an option to make port var dynamic and give it a binding in -main
(def ^:dynamic port 4242)
(defn do-some-work []
(println port))
(defn -main [custom-port]
(binding [port custom-port]
(do-some-work)))
Option 2 scales well and accommodates gracefully if you decide to fire up a server on a random free port for unit tests. Gathering all such settings in a map like {:port 4242 :etc :etc}
is a harmless expedient.
Thank you everyone for all the input! binding definitely went under my radar, I think for my smaller project, I’m probably be using that while I need to try some options for my bigger ones
Hello! I have a question, I am clearly missing something. I going to try to explain my question the best I can.
In this example i'm storing an input value :selected-time
in an atom select-time-state
, that I'm defining in a let in the function select-time
. When I do this - i get the set value "10" in my app, BUT i can not change it on the webpage - even if I have an :on-change
handler.
BUT - if I just def the atom outside of select-time
(the "hidden" defonce - and remove the let ofc) - everything works as expected.
So my question is - why dosen't it allow me to change the state of the atom in the webpage if I def the atom inside the function with let?
#_(defonce select-time-state (atom {:selected-time "10"}))
(defn select-time []
(let [select-time-state (atom {:selected-time "10"})]
[:div.row
[:div.col-4.center
[:input {:type "text"
:placeholder "Select time"
:value (:selected-time @select-time-state)
:on-change #(swap! select-time-state assoc :selected-time (-> % .-target .-value))}]
@select-time-state]]))
(defn countdown-complete []
[:div.row
[:div.col.center
[:h1 "Select the time"]]
[select-time]])
I think this is because the component is re-rendered and the let binding re-evaluated. Or something. Assuming this is reagent. Reagent has three types of components: Form 1, 2, 3, where both 2 and 3 allows you to bind outside the actual component vector, making them act more like your defonce.
Yes, it is reagent! The atom is also a reagent atom.
(:require [reagent.core :as reagent :refer [atom]])
I see. I would do (:require [reagent.core :as r])
and (let [foo (r/atom :foo)])
. So that you easily can use regular atoms and reactive ones in the same namespace. And it is also easier to see on a snippet of code what kind of atom is being used.
Here you can read about the 3 different ways of creating reagent components: https://github.com/reagent-project/reagent/blob/master/doc/CreatingReagentComponents.md
All this said, I often prefer using defonce
for component state over let
. It's much more REPL-friendly.
Clojure newb here, trying/failing to set-up a simple server
Steps taken:
1. Install deps with clj
2. Open new terminal cd into src
3. run clj -M core.clj
Error
Syntax error macroexpanding clojure.core/ns at (core.clj:1:1).
((:require ring.jetty.adapter :as jetty)) - failed: Extra input spec: :clojure.core.specs.alpha/ns-form
deps.edn
{:paths ["src"]
:deps
{org.clojure/clojure {:mvn/version "1.11.1"}
ring/ring-core {:mvn/version "1.9.6"}
ring/ring-jetty-adapter {:mvn/version "1.9.6"}}}
src/core.clj
(ns core
(:require ring.jetty.adapter :as jetty))
(defn handler [request]
{:status 200
:headers {"Content-Type" "text/html"}
:body "welcome aboard"})
(defn -main []
(jetty/run-jetty handler {:port 3000
:join? false}))
You use require not properly.
I fixed the initial error following your example. I now have this new error:
Execution error (FileNotFoundException) at servee/eval138$loading (servee.clj:1).
Could not locate ring/jetty/adapter__init.class, ring/jetty/adapter.clj or ring/jetty/adapter.cljc on classpath.
Running it from the root dir, I get:
Execution error (FileNotFoundException) at
core.clj (No such file or directory)...
clj -M -m core
is the invocation you want. You also need to change
• bad: [ring.jetty.adapter :as jetty]
• good: [ring.adapter.jetty :as jetty]
From clj --help
> main-opt:
> -m, --main ns-name Call the -main function from namespace w/args
This is expecting a namespace name (`ns-name`). So we want to pass it core
and not a filename core.clj
@U11BV7MTK & @U04R4718WAJ. Thank you for the support & patience, I now have a working server 🎉🎉