juxt / aero

A small library for explicit, intentful configuration.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

#keyword doesn't return nil when #env var is missing

fuadsaud opened this issue · comments

Hi!

I don't really understand if this is a bug or a misuse of tagged literals on my part. I want to specify a :logger/min-level key which could contain either a keyword or a complex data structure. I want to source the value either from an environment variable LOGGER_MIN_LEVEL, in which case I would like the string to be coerced into a keyword, or from a #profile dispatch. Here's what I tried:

 :logger/min-level #or [#keyword #env LOGGER_MIN_LEVEL
                        #profile {:default :info

                                  :development
                                  [[#{"some-ns.*"} :trace]
                                   [#{"*"} :info]]

                                  :test
                                  [[#{"some-ns.*"} :trace]
                                   [#{"*"} :info]]}]

In the scenario where the env variable is not set, this returns an empty keyword :. Removing the #keyword tag from the above example makes it work (without the proper coercion, of course). If I understand correctly, #keyword is trying to coerce the vector, which generates the empty keyword. Is this the correct way to approach the problem?

I don't think #or is relevant here particularly. #keyword always converts anything it gets to a keyword:

aero/src/aero/core.cljc

Lines 73 to 77 in 814b000

(defmethod reader 'keyword
[opts tag value]
(if (keyword? value)
value
(keyword (str value))))
so isn't suitable for doing something like some->

Is this perhaps a misunderstanding on my end about application precedence or tagged literals? My intuition led me to interpret the above as:

(#or (#keyword (#env LOGGER_MIN_LEVEL))
     (#profile ...))

But it seems that #keyword applies to both branches of the #or.

(#or (#keyword (#env LOGGER_MIN_LEVEL))
     (#profile ...))

is correct!

But the problem is that (#keyword (#env LOGGER_MIN_LEVEL)) becomes (keyword (str nil)) which is (keyword "") which produces : and that causes your problem!

You could solve this by introducing a new method which behaves a little more like you expect:

 (defmethod aero/reader 'ns/kw 
   [opts tag value] 
   (if (keyword? value) 
     value
     (some-> value keyword))) 

Usage of:

#or [#ns/kw #env LOGGER_MIN_LEVEL #profile {...}]`

should work then.

@SevereOverfl0w ah, that makes perfect of sense, thanks for taking the time to elaborate.