Fork me on GitHub
#clojure
<
2022-11-13
>
Joseph Graham15:11:22

What is the most efficient way to solve the following? I have a vector of strings. I want to convert it to a vector of maps, with an incremented number on each. Example input ["red" "orange" "yellow"] Example output: [{:color "red" :number 1} {:color "orange" :number 2} {:color "yellow" :number 3} ]

dpsutton15:11:14

(let [colors ["red" "orange" "yellow"]] (map (fn [color index] {:color color :number index}) colors (range)))

dpsutton15:11:44

adjust to (rest (range)) if you want to start at 1 not 0

Joseph Graham16:11:59

ah! I didn't realise map took multiple sets of arguments like that. thanks!

Joseph Graham16:11:50

also didn't realise I can call range with no arguments. elegant!

dpsutton16:11:52

yeah map can take multiple collections and is quite handy sometimes. here we use the property that it stops when any of the collections runs out of elements

dpsutton16:11:24

yeah. (range) gives back an infinite sequence but map "terminates" when one of the collections (here, colors) runs out of elements

👍 1
dpsutton16:11:07

there's also map-indexed but i always forget which arg is the index so i just make my own.

(let [colors ["red" "orange" "yellow"]]
  (map-indexed (fn [index color] {:color color :number index}) colors))
({:color "red", :number 0}
 {:color "orange", :number 1}
 {:color "yellow", :number 2})

abdallah gamal09:11:05

(defn color-map [col]
  (map-indexed #(into {} {:color %2 :number (inc %1)}) col))

agorgl16:11:03

Hello! What is the best way to use a different value for a binding when developing something? So far I do have a dev folder with user.clj and I add it to paths with an alias when launching my development repl. I have a def inside another namespace that i want to be different in dev (when developing/running the dev repl) and in prod (when running the app through uberjar)

kwladyka17:11:23

https://clojuredocs.org/clojure.core/with-redefs will replace what you want for code you want

kwladyka17:11:22

but for real you want to use https://github.com/weavejester/integrant and use configuration to startup parts of your system

kwladyka17:11:24

for example this config warm up parts of the system and configure them

(def config
  {:env/variables {:version (app-version)
                   :k_revision (System/getenv "K_REVISION")}
   :db/postgresql {:uri (System/getenv "postgresql")}
   :data-providers/binance {:auth {:api-key (System/getenv "binance_api_key")
                                   :secret-key (System/getenv "binance_secret_key")}}
   :logs/google-json-payload {:level (keyword (System/getenv "log_level"))
                              :is-loggable? (fn [{:keys [^String logger-name ^Level level]}]
                                              (let [level-int (.intValue level)]
                                                (not
                                                  (some (fn [{:keys [logger level]}]
                                                          (and (.startsWith logger-name logger)
                                                               (< level-int (google-json-payload/JUL-levels->int level))))
                                                        [{:logger "org.postgresql" :level :config}
                                                         {:logger "jdk.event.security" :level :config}
                                                         {:logger "okhttp3.internal" :level :config}
                                                         {:logger "sun.net.www.protocol.http.HttpURLConnection" :level :config}]))))
                              :pretty? (nil? (System/getenv "K_REVISION"))}
   })

kwladyka17:11:48

the config file can come also from config.edn

kwladyka17:11:56

it is not in this example, but you can code :db/postgresql as first one to run and service X to run after postgresql, because it depends on it

kwladyka17:11:09

you want to end with such kind of setup, so let’s say with-redefs is easy and fast to go now, but on the end it is worth to use configurations instead of with-redefs

kwladyka17:11:19

at least in my opinion

kwladyka17:11:47

unless you run tests, then with-redefs is perfect

agorgl18:11:29

Ah seems like a good fit! My first thought was that my whole project should have an 'entrypoint' (alternative from -main) that should take a config and pass it down to the specific modules while it initializes them, and in that way I would have a (start prod-conf) in -main and a (start dev-conf) in dev/user.clj

agorgl18:11:45

That did not seem very flexible though as I would need to pass wire/plumb every conf down to each specific module, I was searching more for a way to define maybe a def debug? global definition somewhat like the goog.DEBUG define available in shadow-cljs / re-frame projects

agorgl18:11:30

With integrant can I specify / override part of the configuration in dev/user.clj for development purposes?

kwladyka18:11:59

you can, but you can also use variables (System/getenv "log_level")

kwladyka18:11:19

so far I didn’t have to do things like you are saying

kwladyka18:11:34

I have variables in .envrc and use the same configuration

kwladyka18:11:53

I even don’t have separate dev start up process since I use Integrant

kwladyka18:11:57

:logs/google-json-payload {:level (keyword (System/getenv "log_level"))
                              :is-loggable? (fn [{:keys [^String logger-name ^Level level]}]
                                              (let [level-int (.intValue level)]
                                                (not
                                                  (some (fn [{:keys [logger level]}]
                                                          (and (.startsWith logger-name logger)
                                                               (< level-int (google-json-payload/JUL-levels->int level))))
                                                        [{:logger "org.postgresql" :level :config}
                                                         {:logger "jdk.event.security" :level :config}
                                                         {:logger "okhttp3.internal" :level :config}
                                                         {:logger "sun.net.www.protocol.http.HttpURLConnection" :level :config}]))))
                              :pretty? (nil? (System/getenv "K_REVISION"))}
Like for example here pretty? true is for developing, so I detect if it is deployed in cloud or non with K_REVISION

kwladyka18:11:01

:db/postgresql {:uri (System/getenv "postgresql")} In fact all my code use this config later. It is creating pool of connection which I use everywhere.

kwladyka18:11:21

so it is fine to use this config everywhere, that is what it is for

kwladyka18:11:07

I mean with Integrant you can not only pass parameters to functions which warm up services, but this functions can also return data which you can and should use later in the app

kwladyka18:11:18

At least so for I didn’t have to overwrite anything. I just pass right values in main configuration depends on environment.

kwladyka18:11:43

you can use different config.edn or get values by (System/getenv "K_REVISION")

kwladyka18:11:30

to summary this up: Integrant is something what you have to learn, but in my opinion it is worth to invest this time

kwladyka18:11:48

I don’t no nothing better, than Integrant to start the app

agorgl18:11:11

Ok, I'll check it out!