Ответ 1
Сначала используйте clojure.edn и, в частности, clojure.edn/read. E. g.
(use '(clojure.java [io :as io]))
(defn from-edn
[fname]
(with-open [rdr (-> (io/resource fname)
io/reader
java.io.PushbackReader.)]
(clojure.edn/read rdr)))
Что касается пути config.edn, использующего io/resource, это единственный способ справиться с этим. Поскольку вы, вероятно, захотите сохранить измененный config.edn во время выполнения, вы можете рассчитывать на то, что путь для чтения файлов и писателей, построенных с использованием неквалифицированного имени файла, например
(io/reader "where-am-i.edn")
по умолчанию
(System/getProperty "user.dir")
Учитывая тот факт, что вы можете изменить конфигурацию во время выполнения, вы можете реализовать шаблон, подобный этому (приблизительный эскиз)
;; myapp.userconfig
(def default-config {:k1 "v1"
:k2 2})
(def save-config (partial spit "config.edn"))
(def load-config #(from-edn "config.edn")) ;; see from-edn above
(let [cfg-state (atom (load-config))]
(add-watch cfg-state :cfg-state-watch
(fn [_ _ _ new-state]
(save-config new-state)))
(def get-userconfig #(deref cfg-state))
(def alter-userconfig! (partial swap! cfg-state))
(def reset-userconfig! #(reset! cfg-state default-config)))
В основном этот код обертывает атом, который не является глобальным, и предоставляет набор и получает к нему доступ. Вы можете прочитать его текущее состояние и изменить его как атомы с помощью sth. как (alter-userconfig! assoc :k2 3)
. Для глобального тестирования вы можете reset! userconfig, а также ввести различные пользовательские настройки в ваше приложение (alter-userconfig! (constantly {:k1 300, :k2 212}))
.
Функции, которые требуют userconfig, могут быть написаны как (defn do-sth [cfg arg1 arg2 arg3] ...) И быть протестированным с помощью различных конфигураций, таких как default-userconfig, testconfig1,2,3... Функции, которые управляют userconfig, как в панели пользователя, будут использовать get/alter..! функции.
Также приведенное выше позволяет обернуть часы на userconfig, который автоматически обновляет файл .edn каждый раз при изменении userconfig. Если вы не хотите этого делать, вы можете добавить save-userconfig! которая объединяет содержимое атомов в config.edn. Тем не менее, вы можете создать способ добавить больше часов к атому (например, повторное рендеринг графического интерфейса после изменения пользовательского размера шрифта), который, на мой взгляд, сломал бы форму вышеуказанного шаблона.
Вместо этого, если бы вы имели дело с большим приложением, лучшим подходом было бы определение протокола (с аналогичными функциями, например, в блоке let) для userconfig, и его реализация с различными конструкторами для файла, базы данных, атома ( или что вам нужно для тестирования/разных сценариев использования), используя reify или defrecord. Экземпляр этого может быть передан в приложении, и каждая функция управления состоянием /io должна использовать его вместо глобального.