Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typing full namespaces for keywords in config.edn is tedious #71

Open
SevereOverfl0w opened this issue Apr 7, 2019 · 1 comment
Open

Comments

@SevereOverfl0w
Copy link
Contributor

It might be worth creating some sugar for this, or maybe it's not so bad :).

@SevereOverfl0w
Copy link
Contributor Author

A patch to add support for aliases into the config, there's 3 kinds:

  • Direct alias (:foo becomes :foo.bar.baz/bosh)
  • NS alias (expand xyz in :xyz/foo to com.myproj.xyz/foo)
  • NS prefix (expand proj in :proj.xyz/foo to com.myproj.xyz/foo)

Aliases and prefixes have overlapping functionality. Alias functionality can be replicated with prefixes. This patch needs more work to specify an internally consistent format for the aliases.

From 980ad65006f6e45acaa33313c0b6fd557c6ca09f Mon Sep 17 00:00:00 2001
From: Dominic Monroe <[email protected]>
Date: Sun, 7 Apr 2019 08:05:11 +0100
Subject: [PATCH] Add aliases to config

---
 lib/edge.system/src/edge/system.clj | 113 +++++++++++++++++++++++++++-
 1 file changed, 112 insertions(+), 1 deletion(-)

diff --git a/lib/edge.system/src/edge/system.clj b/lib/edge.system/src/edge/system.clj
index bff5043..d2af043 100644
--- a/lib/edge.system/src/edge/system.clj
+++ b/lib/edge.system/src/edge/system.clj
@@ -5,6 +5,8 @@
   (:require
    [aero.core :as aero]
    [clojure.java.io :as io]
+   [clojure.walk :as walk]
+   [clojure.string :as string]
    [integrant.core :as ig]))
 
 ;; There will be integrant tags in our Aero configuration. We need to
@@ -18,12 +20,121 @@
     (locking lock
       (ig/load-namespaces system-config))))
 
+(defprotocol EdgeNamed
+  (get-namespace [this])
+  (set-namespace [this ns]))
+
+(extend-protocol EdgeNamed
+  clojure.lang.Keyword
+  (get-namespace [k] (namespace k))
+  (set-namespace [k ns] (keyword ns (name k)))
+
+  clojure.lang.Symbol
+  (get-namespace [s] (namespace s))
+  (set-namespace [s ns] (symbol ns (name s))))
+
+(defn- split-ns
+  [ns]
+  (string/split ns #"\."))
+
+(defn- join-ns-segments
+  [ns-segments]
+  (string/join "." ns-segments))
+
+(defn- ns-prefixes
+  [ns]
+  (->> ns
+       split-ns
+       (iterate butlast)
+       (take-while some?)
+       (map join-ns-segments)))
+
+(defn- expand-named
+  [context named]
+  (try
+    (let [named-ns (get-namespace named)]
+      (cond
+        ;; There's a named alias for this key
+        (get-in context [:alias named])
+        (get-in context [:alias named])
+
+        ;; There's an alias for the namespace
+        (get-in context [:require-as (keyword named-ns)])
+        (set-namespace named
+                       (name (get-in context [:require-as (keyword named-ns)])))
+
+        ;; There's a prefix for the namespace
+        (some->> named-ns ns-prefixes (map keyword) (some (:ns-prefix context {})))
+        (let [[prefix replacement]
+              (some #(find (:ns-prefix context) %)
+                    (map keyword (ns-prefixes named-ns)))]
+          (set-namespace
+            named
+            (string/replace-first named-ns
+                                  (name prefix)
+                                  (name replacement))))
+        :else named))
+    (catch Exception e
+      (prn {:context context
+            :named named})
+      (prn (some->> (get-namespace named) ns-prefixes (map keyword)))
+      (throw (ex-info "Error during expansion"
+                      {:context context
+                       :named named}
+                      e)))))
+
+(comment
+  (def ctx {:alias {:foo :edge.system/foo}
+            :require-as {:foo :edge.system.foo}
+            :ns-prefix {:foo :edge.system.bar}})
+
+  (expand-named ctx :foo.baz/abc) ; => :edge.system.bar.baz/abc
+  (expand-named ctx :foo) ; => :edge.system/foo
+  (expand-named ctx :foo/bar) ; => :edge.system.foo/bar
+  )
+
+(defn- expand-config
+  [config]
+  (let [context (::context config)]
+    (walk/postwalk
+      (fn [x]
+        (if (satisfies? EdgeNamed x)
+          (expand-named context x)
+          x))
+      config)))
+
+(comment
+  (expand-config
+    {::context
+     {:ns-prefix {:f :falcon
+                  :fn :falcon.fakenews}}
+
+     :ig/system
+     {:f.pg/embedded nil
+      :fn.foo/article-route {:fn.http.section/article-page 10}}})
+  ;; =>
+  ;{:ig/system {:falcon.pg/embedded nil
+  ;             :falcon.fakenews.foo/article-route
+  ;             {:falcon.fakenews.http.section/article-page 10}}}                                
+  )
+
+(defn- read-config
+  [source given-opts]
+  (let [opts (merge aero/default-opts given-opts {:source source})
+        tag-fn (partial aero/reader opts)
+        wrapped-config (aero/read-config-into-tag-wrapper source)]
+    (-> wrapped-config
+        expand-config
+        (aero/resolve-refs tag-fn)
+        (#'aero/resolve-tag-wrappers tag-fn)
+        (#'aero/realize-deferreds))))
+
 (defn config
   "Read EDN config, with the given aero options. See Aero docs at
   https://github.com/juxt/aero for details."
   [opts]
   (-> (io/resource "config.edn") ;; <1>
-      (aero/read-config opts)) ;; <2>
+      (read-config opts)) ;; <2>
   )
 
 (defn system-config
-- 
2.21.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant