0

In my Clojure project, I'm using a namespace for storing configuration:

(ns clojure-bgproc.settings
  (:require [environ.core :refer [env]]
            [clojure.edn :as edn]))

(def ^:dynamic *app-env* (env :app-env "production"))

(def ^:private config-path
  (if (= *app-env* "test") "settings_test.edn" "settings.edn"))
(def config (-> config-path slurp edn/read-string))
(def db-config (:db config))

For test environment, I use a fixture to redefine *app-env*:

(ns helpers.config
  (:require [clojure-bgproc.settings :refer :all]))

(defn with-test-config [f]
  (with-redefs [*app-env* "test"]
    (f)))

And while the *app-env* is redefined, all the other config variables are not:

FAIL in (app-config-test) (core_test.clj:14)
expected: (s/ends-with? (:dbname db-config) "test")
  actual: (not (s/ends-with? "rmq-reports-development" "test"))

Is there a way for me to easily redefine all the other config variables without me having to manually recompute them?

art-solopov
  • 4,289
  • 3
  • 25
  • 44
  • 3
    Use functions instead of vars? – glts Oct 13 '18 at 13:09
  • I guess it is one way. I was just wondering if there was a better way... – art-solopov Oct 13 '18 at 13:24
  • 1
    @art-solopov This is a perfect case of where functions would be appropriate. You could even make `app-env` a parameter of the function so its data requirements are explicit. Then it doesn't even matter where the data is coming from or where it was defined. Relying on globals being defined is getting pretty side-effecty. – Carcigenicate Oct 13 '18 at 15:05

1 Answers1

1

I think you can do everything you want just using profiles and lein-environ.

It is easy to misconfigure environ. Note it also requires the lein-environ plugin.

Your project.clj:

  :dependencies [
    [environ "1.1.0"]  ...]      ; ********** REQUIRED  *********

  :plugins [[com.jakemccrary/lein-test-refresh "0.22.0"]
            [lein-ancient "0.6.15"]
            [lein-codox "0.10.3"]
            [lein-environ "1.1.0"]]   ; ********** REQUIRED  *********

  :db "jdbc:postgresql://localhost/default"  ; *** default vals ***
  :settings "settings-default.edn"

Then make a profiles.clj:

{:dev  {:env {:db       "jdbc:postgresql://localhost/dev"
              :settings "settings-dev.edn"}}
 :test {:env {:db       "jdbc:postgresql://localhost/test"
              :settings "settings-test.edn"}}}

Then in your proj.core ns:

(ns demo.core
  (:use tupelo.core)
  (:require
    [environ.core :as env]
    ))

(defn -main []
  (println "main -enter")
  (spyx (env/env :db))
  (spyx (env/env :settings)) )

And your test file:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test)
  (:require
    [clojure.string :as str]
    [environ.core :as env]))

(dotest
  (spyx (env/env :db))
  (spyx (env/env :settings))
  )

Run the code:

~/expr/demo > lein run
main -enter
(env/env :db) => "jdbc:postgresql://localhost/dev"
(env/env :settings) => "settings-dev.edn"

Run the tests:

~/expr/demo > lein test

lein test _bootstrap

--------------------------------------
   Clojure 1.10.0-alpha8    Java 11
--------------------------------------

lein test tst.demo.core
(env/env :db) => "jdbc:postgresql://localhost/test"
(env/env :settings) => "settings-test.edn"

Ran 2 tests containing 0 assertions.
0 failures, 0 errors.
Alan Thompson
  • 29,276
  • 6
  • 41
  • 48
  • The problem is, lein-environ seems to be incompatible with CIDER: https://stackoverflow.com/questions/42069550/how-do-i-get-emacs-cider-clojure-mode-to-use-my-test-environment-variables-whe – art-solopov Oct 13 '18 at 20:51