envy icon indicating copy to clipboard operation
envy copied to clipboard

provide a way to extract/print the names of environment variables used?

Open phlummox opened this issue 3 years ago • 0 comments

It'd be nice to be able to quickly produce a list of generated environment variable names being used, when one makes an instance of FromEnv for a type that has a Generics instance. That way, the list can be included in documentation.

The following code provides a method extract to do this:

class Extract a where
  extract :: a -> [String]
  default extract :: (GExtract (Rep a), Generic a) => a -> [String]
  extract x = gExtract (from x) defOption

class GExtract f where
  gExtract :: f a -> Option -> [String]

instance (GExtract a, GExtract b) => GExtract (a :*: b) where
  gExtract (a :*: b) opts = gExtract a opts <> gExtract b opts
instance GExtract a => GExtract (C1 i a) where
  gExtract (M1 x) = gExtract x
instance GExtract a => GExtract (D1 i a) where
  gExtract (M1 x) = gExtract x
instance (Selector s, Var a) => GExtract (S1 s (K1 i a)) where
  gExtract m@(M1 (K1 def)) opts = [toEnvName opts $ selName m]
where `selName` and `snake` are split out into top level functions to avoid duplication (expand for details).
toEnvName :: Option -> String -> String
toEnvName Option{..} xs =
  let name = snake (drop dropPrefixCount xs)
  in if customPrefix == mempty
       then name
       else map toUpper customPrefix ++ "_" ++ name

snake :: String -> String
snake = map toUpper . snakeCase
  where
      applyFirst :: (Char -> Char) -> String -> String
      applyFirst _ []     = []
      applyFirst f [x]    = [f x]
      applyFirst f (x:xs) = f x: xs

      snakeCase :: String -> String
      snakeCase = u . applyFirst toLower
        where u []                 = []
              u (x:xs) | isUpper x = '_' : toLower x : snakeCase xs
                       | otherwise = x : u xs

Is this a feature that could be added to Envy?

phlummox avatar Nov 24 '20 03:11 phlummox