I'm not 100% sure if I understand you correctly. This is what seems closest to 
what I understand you have in mind. Note the comments I added:
    
    
    import std/envvars, std/options
    
    type
      EnvType = object
        m_user: Option[string]
        m_icloud_dir: Option[string]
    
    var Env*: EnvType
    
    ## - `prcname` is the name of the produced helper procedure
    ## - `name` is the field name of the `EnvType`
    ## - `body` is the code inserted for the `isNone` `result = body`
    ## Note:
    ## - assumes all types are of field `Option[string]` (one could either pass 
a
    ##   type or make it much more complicated by trying to determine the type 
from
    ##   the `EnvType` (but that is problematic, because it would need to be a 
`typed` macro
    ##   which clashes with using free identifiers)
    ## - the `{.inject.}` is used to make the `env` available in the body of 
the template
    ## - I switched away from a `do` approach and instead just use a block body
    template define_env(prcname, name, body: untyped): untyped =
      proc `prcname`*(env {.inject.}: var EnvType): string =
        if isNone(env.name):
          result = body
          env.name = some result
        else:
          result = env.name.get
    
    define_env(user, m_user): "USER".getenv
    define_env(icloud_dir, m_icloud_dir): "/Users/" & env.user & 
"/Library/CloudStorage/Box-Box"
    
    when isMainModule:
      echo Env.user
      echo Env.icloud_dir
    
    
    Run

Reply via email to