Browse Source

Generated environment variable documentation

Stephen Starkey 2 years ago
parent
commit
bedd8dde64
9 changed files with 186 additions and 42 deletions
  1. 0
    0
      bin/docs
  2. 0
    0
      bin/pre-push-tests
  3. 46
    0
      defenv.css
  4. 57
    15
      docs/index.html
  5. 3
    1
      project.clj
  6. 18
    15
      spec/defenv/modular_spec.clj
  7. 12
    7
      src/defenv/core.clj
  8. 45
    0
      src/defenv/docs.clj
  9. 5
    4
      src/defenv/usage.clj

bin/docs.sh → bin/docs View File


bin/test-with-checks.sh → bin/pre-push-tests View File


+ 46
- 0
defenv.css View File

@@ -0,0 +1,46 @@
1
+/* defenv documentation standard CSS */
2
+
3
+body {
4
+    width: 800px;
5
+    margin: 0 auto;
6
+}
7
+
8
+dl dd {
9
+    margin: 10px 0 0 0;
10
+    font-size: 1.2em;
11
+}
12
+
13
+dl ul, dl ul li {
14
+    margin: 0;
15
+}
16
+
17
+dl ul {
18
+    padding: 0;
19
+    display: inline-block;
20
+}
21
+
22
+dl ul li {
23
+    padding: 0 0 0 10px;
24
+    list-style-type: none;
25
+    display: inline;
26
+}
27
+
28
+dl ul li:first-child {
29
+    padding: 0;
30
+}
31
+
32
+.masked {
33
+    color: red;
34
+}
35
+
36
+.optional {
37
+    color: green;
38
+}
39
+
40
+.default-value span {
41
+    font-family: monospace;
42
+}
43
+
44
+dl dt span.doc {
45
+    display: block;
46
+}

+ 57
- 15
docs/index.html View File

@@ -2865,8 +2865,8 @@ net.brehaut.ClojureTools = (function (SH) {
2865 2865
     build_tree: build_tree
2866 2866
   };
2867 2867
 })(SyntaxHighlighter);
2868
-</script><title>coreagile/defenv -- Marginalia</title></head><body><table><tr><td class="docs"><div class="header"><h1 class="project-name"><a href="https://defenv.calmabiding.me/">coreagile/defenv</a></h1><h2 class="project-version">0.5.1</h2><br /><p>A simple library for managing environment variables in Clojure</p>
2869
-</div><div class="dependencies"><h3>dependencies</h3><table><tr><td class="dep-name">org.clojure/clojure</td><td class="dotted"><hr /></td><td class="dep-version">1.8.0</td></tr><tr><td class="dep-name">slingshot</td><td class="dotted"><hr /></td><td class="dep-version">0.12.2</td></tr></table></div></td><td class="codes" style="text-align: center; vertical-align: middle;color: #666;padding-right:20px"><br /><br /><br />(this space intentionally left almost blank)</td></tr><tr><td class="docs"><div class="toc"><a name="toc"><h3>namespaces</h3></a><ul><li><a href="#defenv.core">defenv.core</a></li><li><a href="#defenv.usage">defenv.usage</a></li></ul></div></td><td class="codes">&nbsp;</td></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#defenv.core" name="defenv.core"><h1 class="project-name">defenv.core</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><h1>Welcome to defenv</h1>
2868
+</script><title>coreagile/defenv -- Marginalia</title></head><body><table><tr><td class="docs"><div class="header"><h1 class="project-name"><a href="https://defenv.calmabiding.me/">coreagile/defenv</a></h1><h2 class="project-version">1.0.0</h2><br /><p>A simple library for managing environment variables in Clojure</p>
2869
+</div><div class="dependencies"><h3>dependencies</h3><table><tr><td class="dep-name">org.clojure/clojure</td><td class="dotted"><hr /></td><td class="dep-version">1.8.0</td></tr><tr><td class="dep-name">slingshot</td><td class="dotted"><hr /></td><td class="dep-version">0.12.2</td></tr></table></div></td><td class="codes" style="text-align: center; vertical-align: middle;color: #666;padding-right:20px"><br /><br /><br />(this space intentionally left almost blank)</td></tr><tr><td class="docs"><div class="toc"><a name="toc"><h3>namespaces</h3></a><ul><li><a href="#defenv.core">defenv.core</a></li><li><a href="#defenv.usage">defenv.usage</a></li><li><a href="#defenv.docs">defenv.docs</a></li></ul></div></td><td class="codes">&nbsp;</td></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#defenv.core" name="defenv.core"><h1 class="project-name">defenv.core</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><h1>Welcome to defenv</h1>
2870 2870
 
2871 2871
 <p>This library attempts to simplify the management of environment variables.
2872 2872
 Put simply, it's <code>System/getenv</code> on steroids.</p>
@@ -2973,7 +2973,7 @@ doesn't throw exceptions when loading namespaces (a huge pet peeve!).</p>
2973 2973
                         base-value (-&gt; tfn str pretty-demunge)
2974 2974
                         (if masked? &quot;--ERROR MASKED--&quot; (.getMessage e))))
2975 2975
          ::parse-error)))</pre></td></tr><tr><td class="docs">
2976
-</td><td class="codes"><pre class="brush: clojure">(defn- overlay-env [m k {:keys [optional? masked?] env-name :env :as params}]
2976
+</td><td class="codes"><pre class="brush: clojure">(defn- overlay-env [m k {:keys [optional? masked? env-name] :as params}]
2977 2977
   (let [{:keys [tfn params-to-display base-value]} (parse-env env-name params)
2978 2978
         v (try-tfn env-name masked? tfn base-value)]
2979 2979
     (-&gt; m
@@ -2990,18 +2990,18 @@ required variable is missing, not just the one you ask for.</p>
2990 2990
 
2991 2991
 <p>The map should look something like this:</p>
2992 2992
 
2993
-<pre><code>{:ev1 {:env "MY_ENV_VAR"
2993
+<pre><code>{:ev1 {:env-name "MY_ENV_VAR"
2994 2994
        :tfn my-optional-parse-function
2995 2995
        :default "MY OPTIONAL DEFAULT VALUE"
2996 2996
        :masked? true
2997 2997
        :doc "Nice documentation"
2998 2998
        :optional? true}
2999
- :other {:env "OTHER_VAR"}}
2999
+ :other {:env-name "OTHER_VAR"}}
3000 3000
 </code></pre>
3001 3001
 
3002 3002
 <p>In this case, the <code>:ev1</code> key will be filled in with the value of
3003 3003
 <code>MY_ENV_VAR</code>, unless it isn't present, in which case, it will receive the
3004
-value <code>MY OPTIONAL DEFAULT VALUE</code>. Every key except for <code>:env</code> is optional.</p>
3004
+value <code>MY OPTIONAL DEFAULT VALUE</code>. Every key except for <code>:env-name</code> is optional.</p>
3005 3005
 
3006 3006
 <p>In the case of <code>:other</code>, if there is no value for <code>OTHER_VAR</code>, there will be
3007 3007
 an exception thrown much like when attempting to deref a binding generated
@@ -3011,10 +3011,10 @@ by <code>defenv</code>that is required but missing.</p>
3011 3011
   (let [{:keys [env-map display-spec]} (get-env-info env-spec)]
3012 3012
     (throw-usage-if-missing display-spec)
3013 3013
     env-map))</pre></td></tr><tr><td class="docs"><p>Get a single environment variable value. You can use any of the params
3014
-  that you would use in <code>env-&gt;map</code> except <code>:env</code>, which is the <code>env-name</code>.</p>
3014
+  that you would use in <code>env-&gt;map</code> except <code>:env-name</code>, which is the <code>env-name</code>.</p>
3015 3015
 </td><td class="codes"><pre class="brush: clojure">(defn one
3016 3016
   [env-name &amp; params]
3017
-  (:e (env-&gt;map {:e (into {:env env-name} (apply hash-map params))})))</pre></td></tr><tr><td class="docs"><h3>Defining a global environment variable binding</h3>
3017
+  (:e (env-&gt;map {:e (into {:env-name env-name} (apply hash-map params))})))</pre></td></tr><tr><td class="docs"><h3>Defining a global environment variable binding</h3>
3018 3018
 </td><td class="codes"></td></tr><tr><td class="docs">
3019 3019
 </td><td class="codes"><pre class="brush: clojure">(def ^:private global-defined-spec (ref (sorted-map)))
3020 3020
 (def ^:private global-parsed-env (ref (sorted-map)))
@@ -3078,7 +3078,7 @@ missing.</p>
3078 3078
                       (when env-or-fk (concat [env-or-fk] remaining)))
3079 3079
                     (apply hash-map)
3080 3080
                     (add-doc doc-present? doc-or-env))
3081
-        params (assoc params :env env-name)]
3081
+        params (assoc params :env-name env-name)]
3082 3082
     `(do (add-to-global-defined-spec! ~env-name ~params)
3083 3083
          (def ^:dynamic ~b (delay (get-global-env ~env-name))))))</pre></td></tr><tr><td class="docs"><h2>Displaying environment information to your users</h2>
3084 3084
 </td><td class="codes"></td></tr><tr><td class="docs">
@@ -3091,7 +3091,10 @@ missing.</p>
3091 3091
 </td><td class="codes"><pre class="brush: clojure">(defn display-env
3092 3092
   ([] (guarantee-global! (display-env-internal @global-display-spec)))
3093 3093
   ([env-spec]
3094
-   (display-env-internal (:display-spec (get-env-info env-spec)))))</pre></td></tr><tr><td class="docs"><h2>Test fixtures</h2>
3094
+   (display-env-internal (:display-spec (get-env-info env-spec)))))</pre></td></tr><tr><td class="docs"><p>Extract the global environment config as a list of maps</p>
3095
+</td><td class="codes"><pre class="brush: clojure">(defn extract-global-spec
3096
+  [f]
3097
+  (guarantee-global! (map (comp f second) @global-defined-spec)))</pre></td></tr><tr><td class="docs"><h2>Test fixtures</h2>
3095 3098
 </td><td class="codes"></td></tr><tr><td class="docs">
3096 3099
 </td><td class="codes"><pre class="brush: clojure">(defn reset-defined-env!
3097 3100
   []
@@ -3128,13 +3131,14 @@ missing.</p>
3128 3131
 </td><td class="codes"><pre class="brush: clojure">(env/defenv parse-error  &quot;DEFENV_UNPARSEABLE&quot;
3129 3132
   :tfn parse-broken :default &quot;broken&quot;)</pre></td></tr><tr><td class="docs"><h3>Local Map</h3>
3130 3133
 </td><td class="codes"></td></tr><tr><td class="docs">
3131
-</td><td class="codes"><pre class="brush: clojure">(def env-map-spec {:testing {:env &quot;DEFENV_TESTING&quot; :default sensible-default}
3132
-                   :log-level {:env &quot;LOG_LEVEL&quot; :doc &quot;Global log level.&quot;
3134
+</td><td class="codes"><pre class="brush: clojure">(def env-map-spec {:testing {:env-name &quot;DEFENV_TESTING&quot;
3135
+                             :default sensible-default}
3136
+                   :log-level {:env-name &quot;LOG_LEVEL&quot; :doc &quot;Global log level.&quot;
3133 3137
                                :tfn keyword :default &quot;info&quot;}
3134
-                   :should-log? {:env &quot;SHOULD_LOG&quot;
3138
+                   :should-log? {:env-name &quot;SHOULD_LOG&quot;
3135 3139
                                  :doc &quot;Should I log? A boolean.&quot;
3136 3140
                                  :tfn env/parse-bool :default &quot;false&quot;}
3137
-                   :optional {:env &quot;DEFENV_OPT&quot; :optional? true
3141
+                   :optional {:env-name &quot;DEFENV_OPT&quot; :optional? true
3138 3142
                               :doc &quot;A truly optional value.&quot;}})
3139 3143
 (def env-map (env/env-&gt;map env-map-spec))</pre></td></tr><tr><td class="docs">
3140 3144
 </td><td class="codes"><pre class="brush: clojure">(defmacro handle-exception [&amp; body]
@@ -3157,7 +3161,45 @@ missing.</p>
3157 3161
   (env/set-error-print-enabled! true)
3158 3162
   (env/set-err-print-fn! #(log/error %))
3159 3163
   (printf &quot;Exception Printing: %s%n&quot; @testing)
3160
-  (handle-exception @missing))</pre></td></tr><tr><td class="spacer docs">&nbsp;</td><td class="codes" /></tr></table><div class="footer">Generated by <a href="https://github.com/gdeer81/marginalia">Marginalia</a>.&nbsp;&nbsp;Syntax highlighting provided by Alex Gorbatchev's <a href="http://alexgorbatchev.com/SyntaxHighlighter/">SyntaxHighlighter</a><div id="floating-toc"><ul><li class="floating-toc-li" id="floating-toc_defenv.core">defenv.core</li><li class="floating-toc-li" id="floating-toc_defenv.usage">defenv.usage</li></ul></div></div><script type="text/javascript">SyntaxHighlighter.defaults['gutter'] = false;
3164
+  (handle-exception @missing))</pre></td></tr><tr><td class="spacer docs">&nbsp;</td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#defenv.docs" name="defenv.docs"><h1 class="project-name">defenv.docs</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
3165
+</td><td class="codes"><pre class="brush: clojure">(ns defenv.docs
3166
+  (:require [defenv.core :as env]
3167
+            [hiccup.core :as h]))</pre></td></tr><tr><td class="docs"><h1>Documentation Generation</h1>
3168
+</td><td class="codes"></td></tr><tr><td class="docs">
3169
+</td><td class="codes"><pre class="brush: clojure">(defn- env-var-&gt;html [{:keys [env-name default optional? masked? doc]}]
3170
+  [[:dd env-name]
3171
+   [:dt
3172
+    (when (or default optional? masked?)
3173
+      [:ul
3174
+       (when default
3175
+         [:li {:class &quot;default-value&quot;} &quot;Default: &quot;
3176
+          [:span default]])
3177
+       (when optional? [:li {:class &quot;optional&quot;} &quot;optional&quot;])
3178
+       (when masked? [:li {:class &quot;masked&quot;} &quot;masked&quot;])])
3179
+    [:span {:class &quot;doc&quot;} (or doc [:i &quot;No documentation found&quot;])]]])</pre></td></tr><tr><td class="docs">
3180
+</td><td class="codes"><pre class="brush: clojure">(defn- env-&gt;html [header]
3181
+  (h/html
3182
+    [:html
3183
+     [:head
3184
+      [:link {:type &quot;text/css&quot; :href &quot;defenv.css&quot; :rel &quot;stylesheet&quot;}]]
3185
+     [:body
3186
+      [:h1 header]
3187
+      (-&gt;&gt; env-var-&gt;html
3188
+           env/extract-global-spec
3189
+           (reduce concat)
3190
+           (concat [:dl])
3191
+           (into []))]]))</pre></td></tr><tr><td class="docs"><p>Save the current global environment as an HTML file. The <code>header</code> will be
3192
+  emitted as an <code>h1</code> element at the top of the file. The <code>file-name</code> is where
3193
+  the contents will be saved.</p>
3194
+</td><td class="codes"><pre class="brush: clojure">(defn save-html
3195
+  [header file-name]
3196
+  (spit file-name (env-&gt;html header)))</pre></td></tr><tr><td class="docs"><h2>Example usage</h2>
3197
+</td><td class="codes"><pre class="brush: clojure">(defn- example []
3198
+  ;; Once you've loaded up the namespace that causes all the requisite
3199
+  ;; calls to `defenv` to be invoked...
3200
+  (require '[defenv.usage])
3201
+  ;; Then you can...
3202
+  (save-html &quot;defenv environment specification&quot; &quot;test.html&quot;))</pre></td></tr><tr><td class="spacer docs">&nbsp;</td><td class="codes" /></tr></table><div class="footer">Generated by <a href="https://github.com/gdeer81/marginalia">Marginalia</a>.&nbsp;&nbsp;Syntax highlighting provided by Alex Gorbatchev's <a href="http://alexgorbatchev.com/SyntaxHighlighter/">SyntaxHighlighter</a><div id="floating-toc"><ul><li class="floating-toc-li" id="floating-toc_defenv.core">defenv.core</li><li class="floating-toc-li" id="floating-toc_defenv.usage">defenv.usage</li><li class="floating-toc-li" id="floating-toc_defenv.docs">defenv.docs</li></ul></div></div><script type="text/javascript">SyntaxHighlighter.defaults['gutter'] = false;
3161 3203
 SyntaxHighlighter.all();
3162 3204
 
3163 3205
 // hackity hack

+ 3
- 1
project.clj View File

@@ -15,7 +15,7 @@
15 15
 ;     along with defenv.  If not, see <http://www.gnu.org/licenses/>.
16 16
 ;
17 17
 
18
-(defproject coreagile/defenv "0.5.1"
18
+(defproject coreagile/defenv "1.0.0"
19 19
   :description "A simple library for managing environment variables in Clojure"
20 20
   :url "https://defenv.calmabiding.me/"
21 21
   :license {:name "GNU General Public License v3"
@@ -25,6 +25,8 @@
25 25
                  [slingshot "0.12.2"]]
26 26
   :profiles {:dev {:dependencies [[com.taoensso/timbre "4.10.0"]
27 27
                                   [coreagile/specl-slingshot "0.0.1"]
28
+                                  [hiccup/hiccup "1.0.5"]
29
+                                  [org.clojure/tools.cli "0.4.0"]
28 30
                                   [speclj "3.3.2"]]
29 31
                    :plugins [[lein-ancient "0.6.15"]
30 32
                              [lein-bikeshed "0.5.1"]

+ 18
- 15
spec/defenv/modular_spec.clj View File

@@ -22,32 +22,35 @@
22 22
             [specl-slingshot.core :refer :all]
23 23
             [speclj.core :refer :all]))
24 24
 
25
-(def present-vars {:log-level {:env "LOG_LEVEL" :doc "Global log level."
25
+(def present-vars {:log-level {:env-name "LOG_LEVEL" :doc "Global log level."
26 26
                                :tfn keyword :default "info"}
27
-                   :should-log? {:env "SHOULD_LOG"
27
+                   :should-log? {:env-name "SHOULD_LOG"
28 28
                                  :doc "Should I log? A boolean."
29 29
                                  :tfn parse-bool :default "false"}
30
-                   :amount {:env "AMOUNT"
30
+                   :amount {:env-name "AMOUNT"
31 31
                             :doc "An amount. A double."
32 32
                             :tfn parse-double :default "1.5"}
33
-                   :count {:env "COUNT"
33
+                   :count {:env-name "COUNT"
34 34
                            :doc "A count. An int."
35 35
                            :tfn parse-int :default "5"}
36
-                   :fun {:env "FUN" :masked? true}
37
-                   :apples {:env "APPLES" :tfn parse-long :default "10"}
38
-                   :weight {:env "WEIGHT" :tfn parse-float}
39
-                   :eat? {:env "EAT" :doc "Should we eat?"
36
+                   :fun {:env-name "FUN" :masked? true}
37
+                   :apples {:env-name "APPLES" :tfn parse-long :default "10"}
38
+                   :weight {:env-name "WEIGHT" :tfn parse-float}
39
+                   :eat? {:env-name "EAT" :doc "Should we eat?"
40 40
                           :tfn parse-bool :default "false"}
41 41
                    :optional
42
-                   {:env "OPTIONAL" :tfn parse-int :optional? true}})
42
+                   {:env-name "OPTIONAL" :tfn parse-int :optional? true}})
43 43
 
44 44
 (def missing-vars (assoc present-vars
45
-                    :thing {:env "THING" :masked? true}
46
-                    :another {:env "ANOTHER" :doc "This is really important!"}
47
-                    :unparseable {:env "UNPARSEABLE" :doc "Can't parse this."
48
-                                  :default "broken" :tfn parse-int}
49
-                    :bare {:env "BARE"}
50
-                    :unparseable-secret {:env "UNPARSEABLE_SECRET"
45
+                    :thing {:env-name "THING" :masked? true}
46
+                    :another {:env-name "ANOTHER"
47
+                              :doc "This is really important!"}
48
+                    :unparseable {:env-name "UNPARSEABLE"
49
+                                  :doc "Can't parse this."
50
+                                  :default "broken"
51
+                                  :tfn parse-int}
52
+                    :bare {:env-name "BARE"}
53
+                    :unparseable-secret {:env-name "UNPARSEABLE_SECRET"
51 54
                                          :doc "Can't parse this secret."
52 55
                                          :default "secret" :tfn parse-int
53 56
                                          :masked? true}))

+ 12
- 7
src/defenv/core.clj View File

@@ -153,7 +153,7 @@
153 153
                         (if masked? "--ERROR MASKED--" (.getMessage e))))
154 154
          ::parse-error)))
155 155
 
156
-(defn- overlay-env [m k {:keys [optional? masked?] env-name :env :as params}]
156
+(defn- overlay-env [m k {:keys [optional? masked? env-name] :as params}]
157 157
   (let [{:keys [tfn params-to-display base-value]} (parse-env env-name params)
158 158
         v (try-tfn env-name masked? tfn base-value)]
159 159
     (-> m
@@ -174,17 +174,17 @@ required variable is missing, not just the one you ask for.
174 174
 
175 175
 The map should look something like this:
176 176
 
177
-    {:ev1 {:env \"MY_ENV_VAR\"
177
+    {:ev1 {:env-name \"MY_ENV_VAR\"
178 178
            :tfn my-optional-parse-function
179 179
            :default \"MY OPTIONAL DEFAULT VALUE\"
180 180
            :masked? true
181 181
            :doc \"Nice documentation\"
182 182
            :optional? true}
183
-     :other {:env \"OTHER_VAR\"}}
183
+     :other {:env-name \"OTHER_VAR\"}}
184 184
 
185 185
 In this case, the `:ev1` key will be filled in with the value of
186 186
 `MY_ENV_VAR`, unless it isn't present, in which case, it will receive the
187
-value `MY OPTIONAL DEFAULT VALUE`. Every key except for `:env` is optional.
187
+value `MY OPTIONAL DEFAULT VALUE`. Every key except for `:env-name` is optional.
188 188
 
189 189
 In the case of `:other`, if there is no value for `OTHER_VAR`, there will be
190 190
 an exception thrown much like when attempting to deref a binding generated
@@ -196,9 +196,9 @@ by `defenv `that is required but missing."
196 196
 
197 197
 (defn one
198 198
   "Get a single environment variable value. You can use any of the params
199
-  that you would use in `env->map` except `:env`, which is the `env-name`."
199
+  that you would use in `env->map` except `:env-name`, which is the `env-name`."
200 200
   [env-name & params]
201
-  (:e (env->map {:e (into {:env env-name} (apply hash-map params))})))
201
+  (:e (env->map {:e (into {:env-name env-name} (apply hash-map params))})))
202 202
 
203 203
 ;; ### Defining a global environment variable binding
204 204
 
@@ -275,7 +275,7 @@ missing."
275 275
                       (when env-or-fk (concat [env-or-fk] remaining)))
276 276
                     (apply hash-map)
277 277
                     (add-doc doc-present? doc-or-env))
278
-        params (assoc params :env env-name)]
278
+        params (assoc params :env-name env-name)]
279 279
     `(do (add-to-global-defined-spec! ~env-name ~params)
280 280
          (def ^:dynamic ~b (delay (get-global-env ~env-name))))))
281 281
 
@@ -294,6 +294,11 @@ missing."
294 294
   ([env-spec]
295 295
    (display-env-internal (:display-spec (get-env-info env-spec)))))
296 296
 
297
+(defn extract-global-spec
298
+  "Extract the global environment config as a list of maps"
299
+  [f]
300
+  (guarantee-global! (map (comp f second) @global-defined-spec)))
301
+
297 302
 ;; ## Test fixtures
298 303
 
299 304
 (defn reset-defined-env!

+ 45
- 0
src/defenv/docs.clj View File

@@ -0,0 +1,45 @@
1
+(ns defenv.docs
2
+  (:require [defenv.core :as env]
3
+            [hiccup.core :as h]))
4
+
5
+;; # Documentation Generation
6
+
7
+(defn- env-var->html [{:keys [env-name default optional? masked? doc]}]
8
+  [[:dd env-name]
9
+   [:dt
10
+    (when (or default optional? masked?)
11
+      [:ul
12
+       (when default
13
+         [:li {:class "default-value"} "Default: "
14
+          [:span default]])
15
+       (when optional? [:li {:class "optional"} "optional"])
16
+       (when masked? [:li {:class "masked"} "masked"])])
17
+    [:span {:class "doc"} (or doc [:i "No documentation found"])]]])
18
+
19
+(defn- env->html [header]
20
+  (h/html
21
+    [:html
22
+     [:head
23
+      [:link {:type "text/css" :href "defenv.css" :rel "stylesheet"}]]
24
+     [:body
25
+      [:h1 header]
26
+      (->> env-var->html
27
+           env/extract-global-spec
28
+           (reduce concat)
29
+           (concat [:dl])
30
+           (into []))]]))
31
+
32
+(defn save-html
33
+  "Save the current global environment as an HTML file. The `header` will be
34
+  emitted as an `h1` element at the top of the file. The `file-name` is where
35
+  the contents will be saved."
36
+  [header file-name]
37
+  (spit file-name (env->html header)))
38
+
39
+(defn- example-usage []
40
+  (load-file "src/defenv/usage.clj")
41
+  (save-html "defenv environment specification" "test.html"))
42
+
43
+(comment
44
+  (example-usage)
45
+  )

+ 5
- 4
src/defenv/usage.clj View File

@@ -66,13 +66,14 @@
66 66
 
67 67
 ;; ### Local Map
68 68
 
69
-(def env-map-spec {:testing {:env "DEFENV_TESTING" :default sensible-default}
70
-                   :log-level {:env "LOG_LEVEL" :doc "Global log level."
69
+(def env-map-spec {:testing {:env-name "DEFENV_TESTING"
70
+                             :default sensible-default}
71
+                   :log-level {:env-name "LOG_LEVEL" :doc "Global log level."
71 72
                                :tfn keyword :default "info"}
72
-                   :should-log? {:env "SHOULD_LOG"
73
+                   :should-log? {:env-name "SHOULD_LOG"
73 74
                                  :doc "Should I log? A boolean."
74 75
                                  :tfn env/parse-bool :default "false"}
75
-                   :optional {:env "DEFENV_OPT" :optional? true
76
+                   :optional {:env-name "DEFENV_OPT" :optional? true
76 77
                               :doc "A truly optional value."}})
77 78
 (def env-map (env/env->map env-map-spec))
78 79