Envy:   An environment variable manager
1 Quickstart via #lang envy
1.1 Specifying types
1.2 Providing defaults
1.3 Using explicit environment variable names
2 Using Envy with S-expression syntax
2.1 #lang envy/  s-exp
2.2 The envy module
3 API Reference
define-environment
define/  provide-environment
define-environment-variable
6.6.0.3

Envy: An environment variable manager

 #lang envy package: envy

All applications need some degree of configuration. Some options can be provided as command-line flags, but often the configuration is too complex to be specified in this way. For all non-trivial configuration, applications should store configuration in the environment to stay organized and to remain portable.

Envy helps keep environment variables in order by creating a way to declaratively specify all of your app’s environment variables in one place, automatically wrap them in a module, parse them from raw strings into a variety of different datatypes, and even properly associate them with Typed Racket types.

    1 Quickstart via #lang envy

      1.1 Specifying types

      1.2 Providing defaults

      1.3 Using explicit environment variable names

    2 Using Envy with S-expression syntax

      2.1 #lang envy/s-exp

      2.2 The envy module

    3 API Reference

1 Quickstart via #lang envy

To get started, create a module to manage your application’s environment variables (e.g. environment.rkt).

#lang envy

To specify which environment variables your application depends on, specify each variable’s name on a separate line:

#lang envy
some-environment-variable
another-environment-variable

Each line of your environment manifest will produce a variable with the given name bound to the value of the equivalent environment variable. The name of the environment variable will be generated from the name of the Racket variable by converting the identifier to ALL_CAPS, converting dashes to underscores, and stripping question marks. In the above example, Envy would fetch the values for SOME_ENVIRONMENT_VARIABLE and ANOTHER_ENVIRONMENT_VARIABLE.

When the module runs, the values for the specified variables will be loaded, but it’s possible that the variables don’t actually exist in the environment. In this case, an error will be thrown.

#lang envy
some-environment-variable
>

envy: The required environment variable

"SOME_ENVIRONMENT_VARIABLE" is not defined.

If the environment variable does exist, its value will be stored in the binding.

#lang envy
some-environment-variable
another-environment-variable
> some-environment-variable

- : String

"some value"

To use the values of these environment variables in another module, just require the module, optionally with a prefix.

(require (prefix-in env: "environment.rkt"))

1.1 Specifying types

All environment variables are natively strings, but it is extremely common to store other kinds of configuration data, such as booleans and numbers. Envy permits specifying a type with each variable, and it will automatically parse the value to match the specified type.

For example, given the following environment:

HOST=racket-lang.org

PARALLEL=true

THREADS=42

...one could use the following environment definition:

host : String
parallel? : Boolean
threads : Positive-Integer
> host

- : String

"racket-lang.org"

> parallel?

- : Boolean

#t

> threads

- : Integer [more precisely: Positive-Integer]

42

Note that the values are defined with the specified types, useful for Typed Racket users. Also, since String is the default type, including it is not strictly necessary.

1.2 Providing defaults

Sometimes, configuration variables may be optional, in which case it is useful to provide a default value instead of raising an error upon an undefined variable. This can be done with the #:default option.

optional-value #:default #f
> optional-value

- : (U False String)

#f

Note that the type is still properly preserved for Typed Racket users, so if the default value’s type is different from the type of the environment variable, the resulting type will be a union.

1.3 Using explicit environment variable names

Sometimes it is desired to define a variable with a different name from the name used in the environment. This can be done with the #:name option.

custom-name #:name "ENVIRONMENT_NAME"

2 Using Envy with S-expression syntax

Envy’s syntax does not look like traditional S-expressions, but in fact it is just using ordinary Racket syntax with a special reader, called “sweet expressions”. The ordinary, S-expression based syntax is exposed through the envy/s-exp language, as well as the envy module, which can be used in any Typed Racket module via require.

2.1 #lang envy/s-exp

 #lang envy/s-exp package: envy

The envy/s-exp language works exactly like the envy language, but it does not enable the sweet expression reader. Each declaration must be properly grouped.

#lang envy/s-exp
[some-var : Positive-Integer #:default #f]
[another-var : Boolean #:name "CUSTOM NAME"]

This language works just like using the envy module directly, but its body is wrapped in define/provide-environment.

2.2 The envy module

Using envy as a module imports the Envy API, which allows embedding Envy’s functionality in larger modules.

(require envy)
(define/provide-environment
  [some-var : Positive-Integer #:default #f]
  [another-var : Boolean #:name "CUSTOM NAME"])

For full information on all the forms provided by Envy, see the API Reference.

3 API Reference

syntax

(define-environment clause ...)

 
clause = name-id
  | [name-id maybe-type option ...]
     
maybe-type = 
  | : type-id
     
option = #:name env-var-name-expr
  | #:default default-expr
Defines a set of variables to be initialized with values from the environment.

Each name-id is assigned the value of the environment variable with the name env-var-name-expr. If no env-var-name-expr is provided, the environment variable name is inferred based on name-id: the identifier is converted to all caps, all dashes are converted to underscores, and all question marks are stripped.

Before being assigned to name-id, the value of the environment variable is parsed based on type-id. If no type-id is provided, the type is inferred to be String. The following types are supported:

If the specified variable does not exist in the environment, name-id is set to the value of default-expr. If no default-expr is provided, an error is raised.

syntax

(define/provide-environment clause ...)

Exactly the same as define-environment but also provides each name-id.

syntax

(define-environment-variable name-id maybe-type option ...)

Exactly the same as define-environment but only defines a single variable. The syntax is the same as define-environment’s clause.