Help language development. Donate to The Perl Foundation

Trait::Env cpan:SCIMON last updated on 2021-04-29



Trait::Env - Trait to set an attribute from an environment variable.


use Trait::Env;
class Test {
    # Sets from %*ENV{HOME}. Undef if the var doesn't exist
    has $.home is env;

    # Sets from %*ENV{TMPDIR}. Defaults to '/tmp'
    has $.tmpdir is env is default "/tmp";

    # Sets from %*ENV{EXTRA_DIR}. Defaults to '/tmp'
    has $.extra-dir is env( :default</tmp> );

    # Set from %*ENV{WORKDIR}. Dies if not set.
    has $.workdir is env(:required);

    # Set from %*ENV{READ_DIRS.+} ordered lexically
    has is env;

    # Set from %*ENV{PATH} split on ':'
    # has @.path is env(:sep<:>);
    # Or default to the $*DISTRO.path-sep value
    has @.path is env;      

    # Set from %*ENV{NAME_MAP} data split on ';' pairs split on ':'
    # EG a:b;c:d => { "a" => "b", "c" => "d" }
    has is env( :sep<;>, :kvsep<:> );

    # Get all pairs where the key ends with '_POST'
    has is env( :post_match<_POST> );

    # Get all pairs where the Key starts with 'PRE_'
    has %.pre-map is env( :pre_match<PRE_> );

    # Get all pairs where the Key starts with 'PRE_' and ends with '_POST'
    has %.both-map is env( :pre_match<PRE_>, :post_match<_POST> );

    # Parses JSON data
    has $.json-data is env( :json );

# Sets from %*ENV{HOME}. Undef if the var doesn't exist
has $home is env;

# Sets from %*ENV{PATH}. Uses default path seperator
has @path is env;


Trait::Env is exports the new trait is env.

Note the the variable name will be uppercased and any dashes changed to underscores before matching against the environment. This functionality may be modifiable in the future.

For Booleans the standard Empty String == False other String == True works but the string "True" and "False" (any capitalization) will also map to True and False respectively.

If a required attribute is not set the code will raise a X::Trait::Env::Required::Not::Set Exception.

Defaults can be set using the standard is default trait or the :default key. Note that for Positional attributes only the :default key works.

Positional attributes will use the attribute name (after coercing) as the prefix to scan %*ENV for. Any keys starting with that prefix will be ordered by the key name lexically and their values put into the attribute.

Alternatively you can use the :sep key to specify a seperator, in which case the single value will be read based on the name and the list then created by spliting on this seperator.

If there is a single matching environment variable and no :sep key is set then the system will fall back to splitting on the $*DISTRO.path-sep value as a seperator.

Hashes can be single value with a :sep key to specify the seperator between pairs and a :kvsep to specifiy the seperator in each pair between key and value.

Hashes can also be defined by giving a :post_match or :pre_match arguments (or both). Any Environment variable starting with :pre_match is defined or ending with :post-match if defined will be included.

Scalars, Positionals and Associative attributes can all be typed.

Variables can also be defined with is env following the same rules.

Attribute or Variable only is env traits can be loaded individually with Trait::Env::Attribute and Trait::Env::Variable.

Scalar Attributes and Variables can use is env(:json) which will parse the ENV string as a JSON string using JSON::Tiny. You can combine this with the :default and :required options but be aware that the :default value should be a data store NOT a JSON value.


Simon Proctor [email protected]

Thanks to Jonathan Worthington and Elizabeth Mattijsen for giving me the framework to build this on. Any mistakes are mine.


Copyright 2018 Simon Proctor

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.